v2.0 稳定版发布

This commit is contained in:
文派备案 2025-05-28 14:44:57 +08:00
parent b2bd73cb85
commit c177f340dc
14 changed files with 2979 additions and 1835 deletions

View file

@ -1,5 +1,6 @@
/** /**
* WP Archiver 现代化前端脚本 * WP Archiver Modern Frontend Script
* Complete version with all functionality
*/ */
(function($) { (function($) {
@ -8,15 +9,18 @@
const Archiver = { const Archiver = {
config: { config: {
checkInterval: 5000, checkInterval: 3000,
maxChecks: 12, maxChecks: 20,
fadeInDuration: 300, fadeInDuration: 300,
cachePrefix: 'archiver_cache_', cachePrefix: 'archiver_cache_',
debounceDelay: 300 debounceDelay: 300,
retryDelay: 1000,
maxRetries: 3
}, },
currentService: null, currentService: null,
serviceCheckTimers: {}, serviceCheckTimers: {},
loadingCache: {},
init: function() { init: function() {
$(document).ready(() => { $(document).ready(() => {
@ -25,11 +29,12 @@
this.initAdminPage(); this.initAdminPage();
this.initLazyLoading(); this.initLazyLoading();
this.initServiceChecks(); this.initServiceChecks();
this.addNotificationStyles();
}); });
}, },
/** /**
* 初始化元框 * Initialize metabox
*/ */
initMetabox: function() { initMetabox: function() {
const $container = $('#archiver-snapshots'); const $container = $('#archiver-snapshots');
@ -42,7 +47,7 @@
this.currentService = service; this.currentService = service;
// 服务标签切换 // Service tab switching
$('.archiver-service-tab').on('click', (e) => { $('.archiver-service-tab').on('click', (e) => {
e.preventDefault(); e.preventDefault();
const $tab = $(e.currentTarget); const $tab = $(e.currentTarget);
@ -55,10 +60,10 @@
this.loadSnapshots(url, $container, selectedService); this.loadSnapshots(url, $container, selectedService);
}); });
// 延迟加载快照 // Load snapshots with retry mechanism
this.loadSnapshots(url, $container, service); this.loadSnapshots(url, $container, service);
// 立即存档按钮 // Immediate archive button
$('#archiver-immediate-snapshot').on('click', (e) => { $('#archiver-immediate-snapshot').on('click', (e) => {
e.preventDefault(); e.preventDefault();
this.triggerSnapshot(url, this.currentService); this.triggerSnapshot(url, this.currentService);
@ -66,19 +71,21 @@
}, },
/** /**
* 初始化管理栏 * Initialize admin bar
*/ */
initAdminBar: function() { initAdminBar: function() {
const $trigger = $('#wp-admin-bar-archiver-trigger a'); const $trigger = $('#wp-admin-bar-archiver-trigger a');
if (!$trigger.length) return; if (!$trigger.length) return;
// 延迟加载快照计数 // Load snapshot count with delay
const $countItem = $('#wp-admin-bar-archiver-snapshots'); const $countItem = $('#wp-admin-bar-archiver-snapshots');
if ($countItem.length && archiver.url) { if ($countItem.length && archiver.url) {
this.updateAdminBarCount(archiver.url); setTimeout(() => {
this.updateAdminBarCount(archiver.url);
}, 500);
} }
// 触发快照 // Trigger snapshot
$trigger.on('click', (e) => { $trigger.on('click', (e) => {
e.preventDefault(); e.preventDefault();
this.triggerAdminBarSnapshot(); this.triggerAdminBarSnapshot();
@ -86,41 +93,34 @@
}, },
/** /**
* 初始化管理页面 * Initialize admin page
*/ */
initAdminPage: function() { initAdminPage: function() {
// 标签切换 // Tab switching
$('.archiver-tab').on('click', function(e) { $('.settings-tab').on('click', function(e) {
e.preventDefault(); e.preventDefault();
const $tab = $(this); const $tab = $(this);
const tabId = $tab.data('tab'); const tabId = $tab.data('tab');
$('.archiver-tab').removeClass('active'); $('.settings-tab').removeClass('active');
$tab.addClass('active'); $tab.addClass('active');
$('.archiver-tab-content').removeClass('active'); $('.settings-section').hide();
$('#' + tabId).addClass('active'); $('.settings-section[data-section="' + tabId + '"]').show();
// 保存用户偏好 // Save user preference
if (typeof(Storage) !== "undefined") { if (typeof(Storage) !== "undefined") {
localStorage.setItem('archiver_active_tab', tabId); localStorage.setItem('archiver_active_tab', tabId);
} }
}); });
// 恢复上次的标签 // Restore last tab
const savedTab = localStorage.getItem('archiver_active_tab'); const savedTab = localStorage.getItem('archiver_active_tab');
if (savedTab && $(`.archiver-tab[data-tab="${savedTab}"]`).length) { if (savedTab && $(`.settings-tab[data-tab="${savedTab}"]`).length) {
$(`.archiver-tab[data-tab="${savedTab}"]`).trigger('click'); $(`.settings-tab[data-tab="${savedTab}"]`).trigger('click');
} }
// 标签链接 // Test service connection
$('.archiver-tab-link').on('click', function(e) {
e.preventDefault();
const tab = $(this).attr('href').replace('#', '');
$(`.archiver-tab[data-tab="${tab}"]`).trigger('click');
});
// 测试服务连接
$('.test-service').on('click', (e) => { $('.test-service').on('click', (e) => {
e.preventDefault(); e.preventDefault();
const $button = $(e.currentTarget); const $button = $(e.currentTarget);
@ -130,48 +130,50 @@
}, },
/** /**
* 初始化服务检查 * Initialize service checks
*/ */
initServiceChecks: function() { initServiceChecks: function() {
if ($('.archiver-service-card').length === 0) return; if ($('.service-status').length === 0) return;
// 检查所有服务状态 // Check all service statuses
$('.archiver-service-card').each((index, element) => { $('.service-status').each((index, element) => {
const $card = $(element); const $status = $(element);
const service = $card.find('.test-service').data('service'); const serviceId = $status.attr('id').replace('status-', '');
if (service) { if (serviceId) {
this.checkServiceStatus(service); setTimeout(() => {
this.checkServiceStatus(serviceId);
}, index * 200); // Staggered loading
} }
}); });
}, },
/** /**
* 检查服务状态 * Check service status
*/ */
checkServiceStatus: function(service) { checkServiceStatus: function(service) {
const $status = $(`#service-status-${service}`); const $status = $(`#status-${service}`);
if (!$status.length) return; if (!$status.length) return;
// 清除现有定时器 // Clear existing timer
if (this.serviceCheckTimers[service]) { if (this.serviceCheckTimers[service]) {
clearTimeout(this.serviceCheckTimers[service]); clearTimeout(this.serviceCheckTimers[service]);
} }
$status.removeClass('online offline').find('.status-text').text(archiver.i18n.checking); $status.removeClass('online offline').find('.status-text').text(archiver.i18n.checking);
// 模拟检查延迟 // Simulate check with realistic delay
this.serviceCheckTimers[service] = setTimeout(() => { this.serviceCheckTimers[service] = setTimeout(() => {
// 根据服务配置判断状态 // Check if service is enabled
const isEnabled = archiver.enabled_services[service]; const isEnabled = archiver.enabled_services && archiver.enabled_services[service];
const statusClass = isEnabled ? 'online' : 'offline'; const statusClass = isEnabled ? 'online' : 'offline';
const statusText = isEnabled ? archiver.i18n.online : archiver.i18n.offline; const statusText = isEnabled ? archiver.i18n.online : archiver.i18n.offline;
$status.addClass(statusClass).find('.status-text').text(statusText); $status.addClass(statusClass).find('.status-text').text(statusText);
}, 1000); }, 800 + Math.random() * 400);
}, },
/** /**
* 测试服务连接 * Test service connection
*/ */
testServiceConnection: function(service, $button) { testServiceConnection: function(service, $button) {
const originalText = $button.text(); const originalText = $button.text();
@ -185,6 +187,7 @@
service: service, service: service,
nonce: archiver.admin_nonce nonce: archiver.admin_nonce
}, },
timeout: 10000,
success: (response) => { success: (response) => {
if (response.success) { if (response.success) {
this.showNotification(response.data.message, 'success'); this.showNotification(response.data.message, 'success');
@ -193,8 +196,12 @@
this.showNotification(response.data.message || archiver.i18n.test_failed, 'error'); this.showNotification(response.data.message || archiver.i18n.test_failed, 'error');
} }
}, },
error: () => { error: (xhr, status, error) => {
this.showNotification(archiver.i18n.test_failed, 'error'); let message = archiver.i18n.test_failed;
if (status === 'timeout') {
message = 'Connection timeout - service may be slow';
}
this.showNotification(message, 'error');
}, },
complete: () => { complete: () => {
$button.prop('disabled', false).text(originalText); $button.prop('disabled', false).text(originalText);
@ -203,7 +210,7 @@
}, },
/** /**
* 延迟加载 * Initialize lazy loading
*/ */
initLazyLoading: function() { initLazyLoading: function() {
if ('IntersectionObserver' in window) { if ('IntersectionObserver' in window) {
@ -228,23 +235,34 @@
}, },
/** /**
* 加载快照 * Load snapshots with enhanced error handling
*/ */
loadSnapshots: function(url, $container, service = null) { loadSnapshots: function(url, $container, service = null, retryCount = 0) {
// 检查本地缓存 if (retryCount === 0) {
const cacheKey = this.getCacheKey(url, service); // Check local cache first
const cached = this.getCache(cacheKey); const cacheKey = this.getCacheKey(url, service);
if (cached) { const cached = this.getCache(cacheKey);
this.displaySnapshots(cached, $container); if (cached && cached.html) {
// 后台检查更新 this.displaySnapshots(cached, $container);
this.checkForUpdates(url, $container, service); // Background check for updates
return; setTimeout(() => {
this.checkForUpdates(url, $container, service);
}, 2000);
return;
}
} }
// 显示加载状态 // Prevent multiple simultaneous requests
const requestKey = `${url}_${service || 'default'}`;
if (this.loadingCache[requestKey]) {
return;
}
this.loadingCache[requestKey] = true;
// Show loading state
this.showLoading($container); this.showLoading($container);
// 从服务器获取 // Fetch from server
$.ajax({ $.ajax({
url: archiver.ajax_url, url: archiver.ajax_url,
type: 'POST', type: 'POST',
@ -254,40 +272,72 @@
url: url, url: url,
service: service service: service
}, },
timeout: 15000,
success: (response) => { success: (response) => {
delete this.loadingCache[requestKey];
if (response.success) { if (response.success) {
const cacheKey = this.getCacheKey(url, service);
this.setCache(cacheKey, response.data); this.setCache(cacheKey, response.data);
this.displaySnapshots(response.data, $container); this.displaySnapshots(response.data, $container);
} else { } else {
this.showError($container, response.data.message); this.showError($container, response.data?.message || 'Failed to load snapshots');
} }
}, },
error: () => { error: (xhr, status, error) => {
this.showError($container, archiver.i18n.error); delete this.loadingCache[requestKey];
// Retry mechanism
if (retryCount < this.config.maxRetries) {
setTimeout(() => {
this.loadSnapshots(url, $container, service, retryCount + 1);
}, this.config.retryDelay * (retryCount + 1));
$container.html(`
<div class="archiver-loading">
<span class="spinner is-active"></span>
${archiver.i18n.loading} (Retry ${retryCount + 1}/${this.config.maxRetries})
</div>
`);
} else {
let errorMsg = 'Failed to load archive data';
if (status === 'timeout') {
errorMsg = 'Request timeout - archive service may be slow';
} else if (xhr.status === 0) {
errorMsg = 'Network error - please check your connection';
}
this.showError($container, errorMsg);
}
} }
}); });
}, },
/** /**
* 显示快照 * Display snapshots with enhanced UI
*/ */
displaySnapshots: function(data, $container) { displaySnapshots: function(data, $container) {
if (!data.html || data.html.includes('archiver-no-snapshots')) { if (!data.html || data.html.includes('archiver-no-snapshots')) {
$container.html(data.html || '<p class="archiver-no-snapshots">' + archiver.i18n.no_snapshots + '</p>'); const noSnapshotsHtml = `
<div class="archiver-no-snapshots">
<p><em>${archiver.i18n.no_snapshots}</em></p>
<small>Snapshots will appear here after archiving is complete.</small>
</div>
`;
$container.html(data.html || noSnapshotsHtml);
return; return;
} }
$container.hide().html(data.html).fadeIn(this.config.fadeInDuration); $container.hide().html(data.html).fadeIn(this.config.fadeInDuration);
// 添加淡入动画 // Enhanced animations
$container.find('li').each(function(index) { $container.find('.archiver-snapshot-list li').each(function(index) {
$(this).css({ $(this).css({
opacity: 0, opacity: 0,
transform: 'translateY(10px)' transform: 'translateY(10px)'
}).delay(index * 50).animate({ }).delay(index * 100).animate({
opacity: 1 opacity: 1
}, { }, {
duration: 300, duration: 400,
step: function(now, fx) { step: function(now, fx) {
if (fx.prop === 'opacity' && now > 0.5) { if (fx.prop === 'opacity' && now > 0.5) {
$(this).css('transform', 'translateY(0)'); $(this).css('transform', 'translateY(0)');
@ -295,10 +345,18 @@
} }
}); });
}); });
// Add timestamp to links if missing
$container.find('a').each(function() {
const $link = $(this);
if (!$link.attr('title')) {
$link.attr('title', 'Archived snapshot - opens in new tab');
}
});
}, },
/** /**
* 触发快照 * Trigger snapshot with enhanced feedback
*/ */
triggerSnapshot: function(url, service = null) { triggerSnapshot: function(url, service = null) {
const $button = $('#archiver-immediate-snapshot'); const $button = $('#archiver-immediate-snapshot');
@ -317,39 +375,45 @@
url: url, url: url,
service: service service: service
}, },
timeout: 30000,
success: (response) => { success: (response) => {
if (response.success) { if (response.success) {
$status.removeClass('error').addClass('success') $status.removeClass('error').addClass('success')
.html('<span class="dashicons dashicons-yes"></span> ' + response.data.message); .html('<span class="dashicons dashicons-yes"></span> ' + response.data.message);
// 清除缓存并开始轮询 // Clear cache and start monitoring
this.clearCache(this.getCacheKey(url, service)); this.clearCache(this.getCacheKey(url, service));
if (response.data.refresh) { if (response.data.refresh) {
this.startPolling(url, service); this.startPolling(url, service);
} }
// 触发自定义事件 // Trigger custom event
$(document).trigger('archiver:snapshot:success', [url, service]); $(document).trigger('archiver:snapshot:success', [url, service]);
} else { } else {
$status.removeClass('success').addClass('error') $status.removeClass('success').addClass('error')
.html('<span class="dashicons dashicons-warning"></span> ' + response.data.message); .html('<span class="dashicons dashicons-warning"></span> ' +
(response.data?.message || 'Archive request failed'));
} }
}, },
error: () => { error: (xhr, status, error) => {
let errorMsg = archiver.i18n.error;
if (status === 'timeout') {
errorMsg = 'Archive request timeout - please try again';
}
$status.removeClass('success').addClass('error') $status.removeClass('success').addClass('error')
.html('<span class="dashicons dashicons-warning"></span> ' + archiver.i18n.error); .html('<span class="dashicons dashicons-warning"></span> ' + errorMsg);
}, },
complete: () => { complete: () => {
$button.prop('disabled', false).removeClass('updating-message'); $button.prop('disabled', false).removeClass('updating-message');
setTimeout(() => { setTimeout(() => {
$status.fadeOut(); $status.fadeOut();
}, 5000); }, 8000);
} }
}); });
}, },
/** /**
* 管理栏触发快照 * Admin bar snapshot trigger
*/ */
triggerAdminBarSnapshot: function() { triggerAdminBarSnapshot: function() {
const $item = $('#wp-admin-bar-archiver'); const $item = $('#wp-admin-bar-archiver');
@ -365,6 +429,7 @@
url: archiver.url, url: archiver.url,
service: archiver.primary_service service: archiver.primary_service
}, },
timeout: 20000,
success: (response) => { success: (response) => {
$item.removeClass('archiver-active'); $item.removeClass('archiver-active');
if (response.success) { if (response.success) {
@ -377,20 +442,21 @@
this.showNotification(response.message || archiver.i18n.error, 'error'); this.showNotification(response.message || archiver.i18n.error, 'error');
} }
}, },
error: () => { error: (xhr, status) => {
$item.removeClass('archiver-active').addClass('archiver-failure'); $item.removeClass('archiver-active').addClass('archiver-failure');
this.showNotification(archiver.i18n.error, 'error'); const errorMsg = status === 'timeout' ? 'Archive timeout' : archiver.i18n.error;
this.showNotification(errorMsg, 'error');
}, },
complete: () => { complete: () => {
setTimeout(() => { setTimeout(() => {
$item.removeClass('archiver-success archiver-failure'); $item.removeClass('archiver-success archiver-failure');
}, 2000); }, 3000);
} }
}); });
}, },
/** /**
* 更新管理栏计数 * Update admin bar count
*/ */
updateAdminBarCount: function(url) { updateAdminBarCount: function(url) {
const $countItem = $('#wp-admin-bar-archiver-snapshots .ab-label'); const $countItem = $('#wp-admin-bar-archiver-snapshots .ab-label');
@ -405,17 +471,18 @@
url: url, url: url,
service: archiver.primary_service service: archiver.primary_service
}, },
timeout: 10000,
success: (response) => { success: (response) => {
if (response.success && response.data.count !== undefined) { if (response.success && response.data.count !== undefined) {
const count = response.data.count >= 10 ? '10+' : response.data.count; const count = response.data.count >= 10 ? '10+' : response.data.count;
$countItem.text(archiver.i18n.view_all + ' (' + count + ')'); $countItem.text(`${archiver.i18n.view_all} (${count})`);
} }
} }
}); });
}, },
/** /**
* 检查更新 * Check for updates
*/ */
checkForUpdates: function(url, $container, service = null) { checkForUpdates: function(url, $container, service = null) {
$.ajax({ $.ajax({
@ -427,6 +494,7 @@
url: url, url: url,
service: service service: service
}, },
timeout: 8000,
success: (response) => { success: (response) => {
if (response.success && response.data.has_update) { if (response.success && response.data.has_update) {
const cacheKey = this.getCacheKey(url, service); const cacheKey = this.getCacheKey(url, service);
@ -438,7 +506,7 @@
}, },
/** /**
* 开始轮询 * Start polling for updates
*/ */
startPolling: function(url, service = null) { startPolling: function(url, service = null) {
let checkCount = 0; let checkCount = 0;
@ -454,10 +522,20 @@
this.checkForUpdates(url, $container, service); this.checkForUpdates(url, $container, service);
}, this.config.checkInterval); }, this.config.checkInterval);
// Visual indicator for polling
if ($container.length) {
const $indicator = $('<div class="archiver-polling-indicator">Checking for new archives...</div>');
$container.prepend($indicator);
setTimeout(() => {
$indicator.fadeOut(() => $indicator.remove());
}, this.config.checkInterval * 3);
}
}, },
/** /**
* 显示加载状态 * Show loading state
*/ */
showLoading: function($container) { showLoading: function($container) {
const loadingHtml = ` const loadingHtml = `
@ -470,30 +548,61 @@
}, },
/** /**
* 显示错误 * Show error state
*/ */
showError: function($container, message) { showError: function($container, message) {
$container.html('<p class="archiver-error">' + message + '</p>'); const errorHtml = `
<div class="archiver-error">
<p><span class="dashicons dashicons-warning"></span> ${message}</p>
<button class="button button-small archiver-retry">Try Again</button>
</div>
`;
$container.html(errorHtml);
// Retry functionality
$container.find('.archiver-retry').on('click', () => {
const url = $container.data('url');
const service = $container.data('service');
this.loadSnapshots(url, $container, service);
});
}, },
/** /**
* 显示通知 * Show notification
*/ */
showNotification: function(message, type = 'info') { showNotification: function(message, type = 'info') {
// 如果在管理页面,使用 WordPress 通知 // If in admin page, use WordPress notifications
if ($('body').hasClass('wp-admin')) { if ($('body').hasClass('wp-admin')) {
const $notice = $('<div class="notice notice-' + type + ' is-dismissible"><p>' + message + '</p></div>'); const $notice = $(`<div class="notice notice-${type} is-dismissible"><p>${message}</p></div>`);
$('.wrap > h1').after($notice); $('.wrap > h1').after($notice);
// 自动关闭 // Auto dismiss
setTimeout(() => { setTimeout(() => {
$notice.fadeOut(() => $notice.remove()); $notice.fadeOut(() => $notice.remove());
}, 5000); }, 5000);
} else {
// Frontend notification
const $notification = $(`
<div class="archiver-notification archiver-notification-${type}">
${message}
</div>
`);
$('body').append($notification);
setTimeout(() => {
$notification.addClass('show');
}, 100);
setTimeout(() => {
$notification.removeClass('show');
setTimeout(() => $notification.remove(), 300);
}, 4000);
} }
}, },
/** /**
* 缓存管理 * Cache management
*/ */
getCacheKey: function(url, service = null) { getCacheKey: function(url, service = null) {
const serviceKey = service || 'default'; const serviceKey = service || 'default';
@ -508,13 +617,22 @@
if (cached) { if (cached) {
const data = JSON.parse(cached); const data = JSON.parse(cached);
// 5分钟缓存 // 5 minute cache
if (Date.now() - data.timestamp < 300000) { if (Date.now() - data.timestamp < 300000) {
return data.content; return data.content;
} else {
// Clean expired cache
sessionStorage.removeItem(key);
} }
} }
} catch (e) { } catch (e) {
console.warn('Cache read error:', e); console.warn('Archiver cache read error:', e);
// Clean corrupted cache
try {
sessionStorage.removeItem(key);
} catch (cleanError) {
console.warn('Failed to clean corrupted cache:', cleanError);
}
} }
return null; return null;
@ -530,7 +648,9 @@
}; };
sessionStorage.setItem(key, JSON.stringify(cacheData)); sessionStorage.setItem(key, JSON.stringify(cacheData));
} catch (e) { } catch (e) {
console.warn('Cache write error:', e); console.warn('Archiver cache write error:', e);
// Try to clear some space
this.cleanOldCache();
} }
}, },
@ -541,23 +661,157 @@
if (key) { if (key) {
sessionStorage.removeItem(key); sessionStorage.removeItem(key);
} else { } else {
// 清除所有archiver缓存 // Clear all archiver cache
const keys = []; this.cleanOldCache(true);
for (let i = 0; i < sessionStorage.length; i++) {
const k = sessionStorage.key(i);
if (k && k.startsWith(this.config.cachePrefix)) {
keys.push(k);
}
}
keys.forEach(k => sessionStorage.removeItem(k));
} }
} catch (e) { } catch (e) {
console.warn('Cache clear error:', e); console.warn('Archiver cache clear error:', e);
}
},
cleanOldCache: function(clearAll = false) {
if (!this.isStorageAvailable()) return;
try {
const keys = [];
const now = Date.now();
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i);
if (key && key.startsWith(this.config.cachePrefix)) {
if (clearAll) {
keys.push(key);
} else {
try {
const cached = sessionStorage.getItem(key);
if (cached) {
const data = JSON.parse(cached);
// Remove if older than 10 minutes
if (now - data.timestamp > 600000) {
keys.push(key);
}
}
} catch (e) {
// Remove corrupted entries
keys.push(key);
}
}
}
}
keys.forEach(key => {
try {
sessionStorage.removeItem(key);
} catch (e) {
console.warn('Failed to remove cache key:', key, e);
}
});
if (keys.length > 0) {
console.log(`Archiver: Cleaned ${keys.length} cache entries`);
}
} catch (e) {
console.warn('Cache cleanup error:', e);
} }
}, },
/** /**
* 工具函数 * Add notification styles
*/
addNotificationStyles: function() {
if ($('#archiver-notification-styles').length) return;
$('head').append(`
<style id="archiver-notification-styles">
.archiver-notification {
position: fixed;
top: 32px;
right: 20px;
background: #fff;
border-left: 4px solid #00a0d2;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
padding: 12px 16px;
border-radius: 3px;
z-index: 999999;
transform: translateX(100%);
transition: transform 0.3s ease;
max-width: 350px;
word-wrap: break-word;
font-size: 13px;
}
.archiver-notification.show {
transform: translateX(0);
}
.archiver-notification-success {
border-left-color: #46b450;
}
.archiver-notification-error {
border-left-color: #dc3232;
}
.archiver-notification-info {
border-left-color: #00a0d2;
}
.archiver-error {
text-align: center;
padding: 20px;
color: #dc3232;
}
.archiver-error .dashicons {
margin-right: 5px;
}
.archiver-retry {
margin-top: 10px;
}
.archiver-polling-indicator {
background: #e7f3ff;
border: 1px solid #b8dcf2;
color: #0073aa;
padding: 8px 12px;
border-radius: 3px;
margin-bottom: 10px;
font-size: 12px;
text-align: center;
}
.archiver-no-snapshots {
text-align: center;
padding: 20px;
color: #646970;
}
.archiver-no-snapshots small {
display: block;
margin-top: 8px;
font-size: 11px;
}
@media (max-width: 782px) {
.archiver-notification {
top: 46px;
right: 10px;
left: 10px;
max-width: none;
transform: translateY(-100%);
}
.archiver-notification.show {
transform: translateY(0);
}
}
</style>
`);
},
/**
* Utility functions
*/ */
isStorageAvailable: function() { isStorageAvailable: function() {
try { try {
@ -581,7 +835,7 @@
}, },
/** /**
* 防抖函数 * Debounce function
*/ */
debounce: function(func, wait) { debounce: function(func, wait) {
let timeout; let timeout;
@ -593,13 +847,44 @@
clearTimeout(timeout); clearTimeout(timeout);
timeout = setTimeout(later, wait); timeout = setTimeout(later, wait);
}; };
},
/**
* Global error handler
*/
handleGlobalError: function(error, context = 'Unknown') {
console.error(`Archiver Error [${context}]:`, error);
if (typeof error === 'object' && error.message) {
this.showNotification(`Error in ${context}: ${error.message}`, 'error');
}
} }
}; };
// 初始化 // Global error handling
$(document).ajaxError(function(event, xhr, settings, error) {
if (settings.url && settings.url.includes('archiver')) {
console.error('Archiver AJAX Error:', {
url: settings.url,
status: xhr.status,
error: error,
response: xhr.responseText
});
}
});
// Initialize when DOM is ready
Archiver.init(); Archiver.init();
// 暴露到全局 // Expose to global scope
window.WPArchiver = Archiver; window.WPArchiver = Archiver;
// Cleanup on page unload
$(window).on('beforeunload', function() {
// Clean old cache entries before leaving
if (Archiver.isStorageAvailable()) {
Archiver.cleanOldCache();
}
});
})(jQuery); })(jQuery);

View file

@ -1,453 +0,0 @@
/**
* WP Archiver 样式表
*/
/* 管理栏样式 */
#wp-admin-bar-archiver .ab-item {
transition: all .3s ease;
color: #72aee6;
}
#wp-admin-bar-archiver.archiver-success .ab-item {
color: #46b450 !important;
}
#wp-admin-bar-archiver.archiver-failure .ab-item {
color: #dc3232 !important;
}
#wp-admin-bar-archiver .ab-icon.dashicons.dashicons-backup {
top: 2px;
}
#wp-admin-bar-archiver-trigger .ab-icon {
display: inline-block;
float: right !important;
margin: 0 0 0 6px;
opacity: 0;
transition: opacity .3s ease;
vertical-align: middle;
}
#wp-admin-bar-archiver-trigger .ab-icon::before {
content: "\f463";
font-family: dashicons;
font-size: 18px;
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#wp-admin-bar-archiver-trigger.archiver-active .ab-icon,
#wp-admin-bar-archiver.archiver-active .ab-icon {
opacity: 1;
animation: archiver-spin 1s infinite linear;
}
@keyframes archiver-spin {
0% { transform: rotate(0); }
100% { transform: rotate(360deg); }
}
/* 管理页面样式 */
.archiver-admin-wrap {
max-width: 1200px;
}
.archiver-version {
font-size: 13px;
padding-left: 10px;
color: #666;
}
.nav-tab-wrapper {
margin-bottom: 20px;
}
.nav-tab {
border: none;
background: #fff;
border-bottom: 2px solid transparent;
font-weight: 400;
}
.nav-tab:hover {
background: #f0f0f1;
border-bottom-color: #dcdcde;
}
.nav-tab.nav-tab-active {
border-bottom-color: #007cba;
font-weight: 600;
background: #f0f0f1;
}
.archiver-tab-content {
background: #fff;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
}
/* 统计卡片 */
.archiver-stats-container {
display: flex;
gap: 20px;
margin: 20px 0;
flex-wrap: wrap;
}
.archiver-stat-card {
flex: 1;
min-width: 200px;
background: #fff;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 20px;
text-align: center;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
transition: transform 0.2s, box-shadow 0.2s;
}
.archiver-stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 3px 5px rgba(0,0,0,.1);
}
.archiver-stat-card h3 {
margin: 0 0 10px;
font-size: 14px;
font-weight: 500;
color: #646970;
}
.archiver-stat-card .stat-value {
font-size: 24px;
font-weight: 600;
color: #1d2327;
line-height: 1;
}
.stat-subtitle {
font-size: 12px;
color: #666;
margin-top: 8px;
}
/* 缓存分布 */
.cache-distribution {
margin-top: 10px;
}
.cache-bar {
display: flex;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
}
.cache-segment {
height: 100%;
transition: width 0.3s ease;
position: relative;
}
.cache-segment.hot { background: #e74c3c; }
.cache-segment.warm { background: #f39c12; }
.cache-segment.cold { background: #3498db; }
.cache-segment.frozen { background: #95a5a6; }
.cache-legend {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 10px;
font-size: 12px;
}
.legend-item {
display: flex;
align-items: center;
}
.legend-color {
width: 12px;
height: 12px;
border-radius: 2px;
margin-right: 5px;
}
.legend-color.hot { background: #e74c3c; }
.legend-color.warm { background: #f39c12; }
.legend-color.cold { background: #3498db; }
.legend-color.frozen { background: #95a5a6; }
/* 待处理列表 */
.archiver-pending-list {
max-height: 300px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
background: #f9f9f9;
margin: 15px 0;
}
.archiver-pending-list ul {
margin: 0;
padding: 0;
list-style: none;
}
.archiver-pending-list li {
padding: 8px 0;
border-bottom: 1px solid #eee;
word-break: break-all;
font-family: monospace;
font-size: 13px;
color: #555;
}
.archiver-pending-list li:last-child {
border-bottom: none;
}
/* 元框样式 */
#archiver_post,
#archiver_terms {
background: #fff;
}
#archiver-snapshots {
min-height: 60px;
position: relative;
}
#archiver-snapshots ul {
margin: 0;
padding: 0;
list-style: none;
}
#archiver-snapshots li {
padding: 8px 0;
border-bottom: 1px solid #eee;
transition: all 0.3s ease;
}
#archiver-snapshots li:last-child {
border-bottom: none;
}
#archiver-snapshots li:hover {
background: #f5f5f5;
padding-left: 5px;
}
#archiver-snapshots a {
text-decoration: none;
color: #2271b1;
}
#archiver-snapshots a:hover {
text-decoration: underline;
color: #135e96;
}
/* 加载状态 */
.archiver-loading {
text-align: center;
padding: 20px;
color: #666;
}
.archiver-loading .spinner {
float: none;
margin: 0 5px 0 0;
}
/* 状态消息 */
#archiver-status {
display: inline-block;
vertical-align: middle;
color: #646970;
}
#archiver-status.success {
color: #46b450;
}
#archiver-status.error {
color: #dc3232;
}
#archiver-status .dashicons {
vertical-align: middle;
margin-right: 3px;
}
/* 按钮样式 */
#archiver-immediate-snapshot {
margin-top: 10px;
}
#archiver-immediate-snapshot.updating-message:before {
content: "\f463";
display: inline-block;
font-family: dashicons;
animation: archiver-spin 1s infinite linear;
margin-right: 5px;
}
.archiver-view-all {
font-size: 13px;
}
/* 工具区域 */
.archiver-tools-section {
margin-bottom: 30px;
padding-bottom: 30px;
border-bottom: 1px solid #ddd;
}
.archiver-tools-section:last-child {
border-bottom: none;
}
.archiver-tools-section h3 {
margin-top: 0;
}
.archiver-tool-form {
margin-top: 15px;
}
/* 缓存操作 */
.archiver-cache-actions {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #ddd;
}
.archiver-cache-actions .button {
margin-right: 5px;
}
/* 关于页面 */
.archiver-about-content {
max-width: 800px;
}
.archiver-about-content ul {
list-style: disc;
padding-left: 20px;
}
.archiver-about-content li {
margin-bottom: 8px;
}
/* 响应式设计 */
@media (max-width: 782px) {
.archiver-stats-container {
flex-direction: column;
}
.archiver-stat-card {
width: 100%;
min-width: unset;
}
.cache-legend {
flex-wrap: wrap;
}
.nav-tab-wrapper {
display: flex;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.nav-tab {
white-space: nowrap;
flex-shrink: 0;
}
}
/* 暗色模式支持 */
@media (prefers-color-scheme: dark) {
.wp-admin.admin-color-modern .archiver-stat-card,
.wp-admin.admin-color-modern .archiver-tab-content {
background: #1e1e1e;
border-color: #3c434a;
color: #ccc;
}
.wp-admin.admin-color-modern .archiver-stat-card h3 {
color: #aaa;
}
.wp-admin.admin-color-modern .stat-value {
color: #fff;
}
.wp-admin.admin-color-modern .archiver-pending-list {
background: #2c3338;
border-color: #3c434a;
}
}
/* 动画效果 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.archiver-snapshot-list li {
animation: fadeInUp 0.3s ease forwards;
}
/* 工具提示 */
[title] {
position: relative;
}
.cache-segment:hover::after {
content: attr(title);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #333;
color: #fff;
padding: 5px 10px;
border-radius: 3px;
font-size: 12px;
white-space: nowrap;
z-index: 1000;
pointer-events: none;
}
/* 缓存统计区域 */
.archiver-cache-stats {
background: #f8f9fa;
border: 1px solid #e1e4e8;
border-radius: 6px;
padding: 20px;
margin: 20px 0;
}
.archiver-cache-stats h2 {
margin-top: 0;
font-size: 18px;
color: #1d2327;
}

View file

@ -1 +0,0 @@
#wp-admin-bar-archiver .ab-item{transition:all .3s ease;color:#72aee6}#wp-admin-bar-archiver.archiver-success .ab-item{color:#46b450!important}#wp-admin-bar-archiver.archiver-failure .ab-item{color:#dc3232!important}#wp-admin-bar-archiver .ab-icon.dashicons.dashicons-backup{top:2px}#wp-admin-bar-archiver-trigger .ab-icon{display:inline-block;float:right!important;margin:0 0 0 6px;opacity:0;transition:opacity .3s ease;vertical-align:middle}#wp-admin-bar-archiver-trigger .ab-icon::before{content:"\f463";font-family:dashicons;font-size:18px;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#wp-admin-bar-archiver-trigger.archiver-active .ab-icon{opacity:1;animation:archiver-spin 1s infinite linear}@keyframes archiver-spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.nav-tab{border:0 solid #c3c4c7;background:#fff}.nav-tab.nav-tab-active{border-bottom:2px solid #007cba;font-weight:600;background:#f0f0f1}.nav-tab:hover:not(.active){background:#f0f0f1;border-bottom-color:#dcdcde}.card{background:#fff;border:1px solid #ccd0d4;border-radius:4px;max-width:unset;margin-top:20px;padding:20px}.postbox{border:0 solid #c3c4c7;background:#ffffff00}.archiver-stats-container{display:flex;gap:20px;margin:0 0 20px}.archiver-stat-card{flex:1;background:#fff;border:1px solid #ccd0d4;border-radius:4px;padding:15px;text-align:center;box-shadow:0 1px 1px rgba(0,0,0,.04)}.archiver-stat-card h3{margin:0 0 10px;font-size:14px;font-weight:500;color:#646970}.archiver-stat-card .stat-value{font-size:18px;font-weight:600;color:#1d2327}.archiver-pending-list{max-height:300px;overflow-y:auto;border:1px solid #ddd;padding:10px;background:#f9f9f9;margin:0 0 20px}.archiver-pending-list ul{margin:0;padding:0;list-style:none}.archiver-pending-list li{padding:5px 0;border-bottom:1px solid #eee;word-break:break-all}.archiver-pending-list li:last-child{border-bottom:none}@media (max-width:782px){.archiver-stats-container{flex-direction:column}.archiver-stat-card{width:100%}}#archiver_post,#archiver_terms{background:#fff;border-radius:4px}#archiver-snapshots ul{margin:0;padding:0;list-style:none}#archiver-snapshots li{padding:5px 0;border-bottom:1px solid #eee}#archiver-snapshots li:last-child{border-bottom:none}#archiver-snapshots a{text-decoration:none;color:#2271b1}#archiver-snapshots a:hover{text-decoration:underline}#archiver-status{vertical-align:middle;color:#646970}#archiver-status .dashicons{vertical-align:middle;margin-right:3px}#archiver-immediate-snapshot{margin-top:10px}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
<?php <?php
/** /**
* WP Archiver 缓存管理系统 * WP Archiver Cache Management System - Fixed Version
*/ */
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
@ -17,35 +17,69 @@ class Archiver_Cache {
'frozen' => MONTH_IN_SECONDS 'frozen' => MONTH_IN_SECONDS
]; ];
// 添加服务特定的缓存前缀 // Service-specific cache prefix
private $cache_prefix = 'archiver_'; private $cache_prefix = 'archiver_';
// 批处理优化 // Batch processing optimization
private $batch_size = 3; private $batch_size = 10;
private $max_retries = 3; private $max_retries = 3;
public function __construct() { public function __construct() {
global $wpdb; global $wpdb;
$this->table_name = $wpdb->prefix . 'archiver_cache'; $this->table_name = $wpdb->prefix . 'archiver_cache';
$this->batch_size = apply_filters('archiver_batch_size', 3); $this->batch_size = get_option('archiver_batch_size', 10);
} }
/** /**
* 获取快照数据(支持多服务) * Get available services with fallback
*/
private function get_available_services() {
if (defined('ARCHIVER_SERVICES') && is_array(ARCHIVER_SERVICES)) {
return ARCHIVER_SERVICES;
}
// Fallback services if constant is not defined
return array(
'wenpai' => array(
'name' => 'WenPai Archive',
'save_url' => 'https://web.wenpai.net/save/',
'fetch_url' => 'https://web.wenpai.net/cdx/',
'view_url' => 'https://web.wenpai.net/web/',
'enabled' => true
),
'wayback' => array(
'name' => 'Internet Archive',
'save_url' => 'https://web.archive.org/save/',
'fetch_url' => 'https://web.archive.org/cdx/search/cdx',
'view_url' => 'https://web.archive.org/web/',
'enabled' => true
),
'archive_today' => array(
'name' => 'Archive.today',
'save_url' => 'https://archive.today/?run=1&url=',
'fetch_url' => 'https://archive.today/',
'view_url' => 'https://archive.today/',
'enabled' => false
)
);
}
/**
* Get snapshot data (supports multiple services)
*/ */
public function get_snapshots($url, $service = null, $force_refresh = false) { public function get_snapshots($url, $service = null, $force_refresh = false) {
if (!get_option('archiver_cache_enabled', true)) { if (!get_option('archiver_cache_enabled', true)) {
return $this->fetch_from_archive_service($url, $service); return $this->fetch_from_archive_service($url, $service);
} }
// 如果没有指定服务,使用主服务 // If no service specified, use primary service
if (!$service) { if (!$service) {
$service = get_option('archiver_primary_service', 'wenpai'); $service = get_option('archiver_primary_service', 'wenpai');
} }
$url_hash = md5($url . '_' . $service); $url_hash = md5($url . '_' . $service);
// 1. 检查内存缓存 // 1. Check memory cache
if (!$force_refresh) { if (!$force_refresh) {
$memory_key = $this->cache_prefix . 'snap_' . $url_hash; $memory_key = $this->cache_prefix . 'snap_' . $url_hash;
$cached_data = wp_cache_get($memory_key, 'archiver'); $cached_data = wp_cache_get($memory_key, 'archiver');
@ -56,24 +90,25 @@ class Archiver_Cache {
} }
} }
// 2. 检查数据库缓存 // 2. Check database cache
if (!$force_refresh) { if (!$force_refresh) {
$db_cache = $this->get_from_database($url_hash, $service); $db_cache = $this->get_from_database($url_hash, $service);
if ($db_cache !== false) { if ($db_cache !== false) {
$memory_key = $this->cache_prefix . 'snap_' . $url_hash;
wp_cache_set($memory_key, $db_cache, 'archiver', HOUR_IN_SECONDS); wp_cache_set($memory_key, $db_cache, 'archiver', HOUR_IN_SECONDS);
return $db_cache; return $db_cache;
} }
} }
// 3. 添加到后台队列(带服务信息) // 3. Add to background queue (with service info)
$this->queue_for_update($url, $service, false); $this->queue_for_update($url, $service, false);
// 4. 返回过期数据或空数组 // 4. Return stale data or empty array
return $this->get_stale_data($url_hash, $service) ?: []; return $this->get_stale_data($url_hash, $service) ?: [];
} }
/** /**
* 从数据库获取缓存 * Get cache from database
*/ */
private function get_from_database($url_hash, $service = 'wenpai') { private function get_from_database($url_hash, $service = 'wenpai') {
global $wpdb; global $wpdb;
@ -91,7 +126,7 @@ class Archiver_Cache {
$this->update_access_stats($url_hash, $service); $this->update_access_stats($url_hash, $service);
$data = maybe_unserialize($row->snapshot_data); $data = maybe_unserialize($row->snapshot_data);
// 根据访问频率提升缓存级别 // Promote cache level based on access frequency
if ($row->api_calls_saved > 10 && $row->cache_type !== 'hot') { if ($row->api_calls_saved > 10 && $row->cache_type !== 'hot') {
$this->promote_cache($url_hash, $service, 'hot'); $this->promote_cache($url_hash, $service, 'hot');
} }
@ -100,7 +135,7 @@ class Archiver_Cache {
} }
/** /**
* 获取过期数据 * Get stale data
*/ */
private function get_stale_data($url_hash, $service = 'wenpai') { private function get_stale_data($url_hash, $service = 'wenpai') {
global $wpdb; global $wpdb;
@ -117,7 +152,7 @@ class Archiver_Cache {
} }
/** /**
* 保存快照数据 * Save snapshot data
*/ */
public function save_snapshots($url, $snapshots, $service = 'wenpai') { public function save_snapshots($url, $snapshots, $service = 'wenpai') {
global $wpdb; global $wpdb;
@ -140,23 +175,25 @@ class Archiver_Cache {
'status' => 'active' 'status' => 'active'
]; ];
$wpdb->replace($this->table_name, $data); $result = $wpdb->replace($this->table_name, $data);
// 更新内存缓存 if ($result !== false) {
$memory_key = $this->cache_prefix . 'snap_' . $url_hash; // Update memory cache
wp_cache_set($memory_key, $snapshots, 'archiver', HOUR_IN_SECONDS); $memory_key = $this->cache_prefix . 'snap_' . $url_hash;
wp_cache_set($memory_key, $snapshots, 'archiver', HOUR_IN_SECONDS);
// 更新统计 // Update statistics
$this->increment_archived_count(); $this->increment_archived_count();
}
return true; return $result !== false;
} }
/** /**
* 确定缓存类型 * Determine cache type
*/ */
private function determine_cache_type($url) { private function determine_cache_type($url) {
// 首页:热数据 // Homepage: hot data
if ($url === home_url() || $url === home_url('/')) { if ($url === home_url() || $url === home_url('/')) {
return 'hot'; return 'hot';
} }
@ -177,12 +214,12 @@ class Archiver_Cache {
} }
/** /**
* 添加到更新队列(支持多服务) * Add to update queue (supports multiple services)
*/ */
public function queue_for_update($url, $service = null, $priority = false) { public function queue_for_update($url, $service = null, $priority = false) {
$queue = get_option('archiver_background_queue', []); $queue = get_option('archiver_background_queue', []);
// 如果没有指定服务,使用所有启用的服务 // If no service specified, use all enabled services
if (!$service) { if (!$service) {
$enabled_services = get_option('archiver_services', array('wenpai' => true)); $enabled_services = get_option('archiver_services', array('wenpai' => true));
foreach ($enabled_services as $service_id => $enabled) { foreach ($enabled_services as $service_id => $enabled) {
@ -194,25 +231,25 @@ class Archiver_Cache {
$this->add_to_queue($queue, $url, $service, $priority); $this->add_to_queue($queue, $url, $service, $priority);
} }
// 限制队列大小 // Limit queue size
$max_queue_size = apply_filters('archiver_queue_limit', 100); $max_queue_size = get_option('archiver_max_queue_size', 500);
$queue = array_slice($queue, 0, $max_queue_size); $queue = array_slice($queue, 0, $max_queue_size);
update_option('archiver_background_queue', $queue); update_option('archiver_background_queue', $queue);
// 触发后台处理 // Trigger background processing
if (!wp_next_scheduled('archiver_process_background_queue')) { if (!wp_next_scheduled('archiver_process_background_queue')) {
wp_schedule_single_event(time() + 10, 'archiver_process_background_queue'); wp_schedule_single_event(time() + 10, 'archiver_process_background_queue');
} }
} }
/** /**
* 添加单个项目到队列 * Add single item to queue
*/ */
private function add_to_queue(&$queue, $url, $service, $priority) { private function add_to_queue(&$queue, $url, $service, $priority) {
$item = array('url' => $url, 'service' => $service, 'retries' => 0); $item = array('url' => $url, 'service' => $service, 'retries' => 0);
// 检查是否已存在 // Check if already exists
foreach ($queue as $existing) { foreach ($queue as $existing) {
if (is_array($existing) && $existing['url'] === $url && $existing['service'] === $service) { if (is_array($existing) && $existing['url'] === $url && $existing['service'] === $service) {
return; return;
@ -227,7 +264,7 @@ class Archiver_Cache {
} }
/** /**
* 处理后台队列 * Process background queue
*/ */
public function process_background_queue() { public function process_background_queue() {
$queue = get_option('archiver_background_queue', []); $queue = get_option('archiver_background_queue', []);
@ -236,13 +273,13 @@ class Archiver_Cache {
return; return;
} }
// 每次处理批量URL // Process batch URLs each time
$batch = array_splice($queue, 0, $this->batch_size); $batch = array_splice($queue, 0, $this->batch_size);
$failed_items = array(); $failed_items = array();
foreach ($batch as $item) { foreach ($batch as $item) {
if (!is_array($item)) { if (!is_array($item)) {
// 兼容旧格式 // Compatible with old format
$item = array('url' => $item, 'service' => 'wenpai', 'retries' => 0); $item = array('url' => $item, 'service' => 'wenpai', 'retries' => 0);
} }
@ -258,20 +295,20 @@ class Archiver_Cache {
} }
} }
// 将失败的项目重新加入队列末尾 // Re-add failed items to end of queue
$queue = array_merge($queue, $failed_items); $queue = array_merge($queue, $failed_items);
// 更新队列 // Update queue
update_option('archiver_background_queue', $queue); update_option('archiver_background_queue', $queue);
// 如果还有待处理项,继续安排 // Continue scheduling if more items pending
if (!empty($queue)) { if (!empty($queue)) {
wp_schedule_single_event(time() + 30, 'archiver_process_background_queue'); wp_schedule_single_event(time() + 30, 'archiver_process_background_queue');
} }
} }
/** /**
* 从存档服务获取并缓存数据 * Fetch and cache snapshots from archive service
*/ */
public function fetch_and_cache_snapshots($url, $service = 'wenpai') { public function fetch_and_cache_snapshots($url, $service = 'wenpai') {
$snapshots = $this->fetch_from_archive_service($url, $service); $snapshots = $this->fetch_from_archive_service($url, $service);
@ -285,14 +322,14 @@ class Archiver_Cache {
} }
/** /**
* 从存档服务获取数据 * Fetch data from archive service
*/ */
private function fetch_from_archive_service($url, $service = null) { private function fetch_from_archive_service($url, $service = null) {
if (!$service) { if (!$service) {
$service = get_option('archiver_primary_service', 'wenpai'); $service = get_option('archiver_primary_service', 'wenpai');
} }
$services = ARCHIVER_SERVICES; $services = $this->get_available_services();
if (!isset($services[$service])) { if (!isset($services[$service])) {
return false; return false;
} }
@ -313,114 +350,187 @@ class Archiver_Cache {
} }
/** /**
* Wayback Machine 获取数据 * Fetch data from Wayback Machine
*/ */
private function fetch_from_wayback($url) { private function fetch_from_wayback($url) {
$services = $this->get_available_services();
$api_url = add_query_arg([ $api_url = add_query_arg([
'url' => $url, 'url' => $url,
'output' => 'json', 'output' => 'json',
'limit' => 10 'limit' => 20,
], ARCHIVER_SERVICES['wayback']['fetch_url']); 'fl' => 'timestamp,original,statuscode,mimetype,length'
], $services['wayback']['fetch_url']);
$response = wp_remote_get($api_url, [ $response = wp_remote_get($api_url, [
'timeout' => 30, 'timeout' => 30,
'sslverify' => true, 'sslverify' => true,
'headers' => [ 'headers' => [
'User-Agent' => 'WP-Archiver/' . ARCHIVER_VERSION 'User-Agent' => 'WP-Archiver/' . ARCHIVER_VERSION . ' (WordPress/' . get_bloginfo('version') . ')'
] ]
]); ]);
if (is_wp_error($response)) { if (is_wp_error($response)) {
if (function_exists('archiver_handle_error')) {
archiver_handle_error('Wayback API error: ' . $response->get_error_message());
}
return false; return false;
} }
if (wp_remote_retrieve_response_code($response) !== 200) { $response_code = wp_remote_retrieve_response_code($response);
if ($response_code !== 200) {
if (function_exists('archiver_handle_error')) {
archiver_handle_error('Wayback API returned status: ' . $response_code);
}
return false; return false;
} }
$body = wp_remote_retrieve_body($response); $body = wp_remote_retrieve_body($response);
if (empty($body)) {
return false;
}
$data = json_decode($body, true); $data = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
if (function_exists('archiver_handle_error')) {
archiver_handle_error('Wayback API JSON decode error: ' . json_last_error_msg());
}
return false;
}
if (empty($data) || !is_array($data)) { if (empty($data) || !is_array($data)) {
return false; return array(); // Return empty array instead of false
} }
return $this->process_wayback_response($data); return $this->process_wayback_response($data);
} }
/** /**
* WenPai Archive 获取数据 * Fetch data from WenPai Archive
*/ */
private function fetch_from_wenpai($url) { private function fetch_from_wenpai($url) {
$services = $this->get_available_services();
$api_url = add_query_arg([ $api_url = add_query_arg([
'url' => $url, 'url' => $url,
'output' => 'json', 'output' => 'json',
], ARCHIVER_SERVICES['wenpai']['fetch_url']); 'limit' => 20,
'fl' => 'timestamp,original,statuscode'
], $services['wenpai']['fetch_url']);
$response = wp_remote_get($api_url, [ $response = wp_remote_get($api_url, [
'timeout' => 30, 'timeout' => 30,
'sslverify' => false, // WenPai 可能使用自签名证书 'sslverify' => false, // WenPai might use self-signed certificate
'headers' => [ 'headers' => [
'User-Agent' => 'WP-Archiver/' . ARCHIVER_VERSION 'User-Agent' => 'WP-Archiver/' . ARCHIVER_VERSION . ' (WordPress/' . get_bloginfo('version') . ')'
] ]
]); ]);
if (is_wp_error($response)) { if (is_wp_error($response)) {
if (function_exists('archiver_handle_error')) {
archiver_handle_error('WenPai API error: ' . $response->get_error_message());
}
return false; return false;
} }
if (wp_remote_retrieve_response_code($response) !== 200) { $response_code = wp_remote_retrieve_response_code($response);
if ($response_code !== 200) {
if (function_exists('archiver_handle_error')) {
archiver_handle_error('WenPai API returned status: ' . $response_code);
}
return false; return false;
} }
$body = wp_remote_retrieve_body($response); $body = wp_remote_retrieve_body($response);
$data = json_decode($body, true); if (empty($body)) {
return array(); // Return empty array instead of false
if (empty($data) || !is_array($data)) {
return false;
} }
return $this->process_wayback_response($data); // 使用相同的处理方法 $data = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
// Try to parse as plain text (CDX format)
return $this->parse_cdx_response($body);
}
if (empty($data) || !is_array($data)) {
return array();
}
return $this->process_wayback_response($data); // Use same processing method
} }
/** /**
* 处理 Wayback Machine 响应 * Parse CDX format response
*/
private function parse_cdx_response($body) {
$lines = explode("\n", trim($body));
if (empty($lines)) {
return array();
}
$snapshots = array();
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) continue;
$parts = preg_split('/\s+/', $line);
if (count($parts) >= 3) {
$snapshots[] = array(
'timestamp' => $parts[1],
'original' => $parts[2],
'statuscode' => isset($parts[4]) ? $parts[4] : '200'
);
}
}
return array_reverse(array_slice($snapshots, -20)); // Return latest 20
}
/**
* Process Wayback Machine response
*/ */
private function process_wayback_response($data) { private function process_wayback_response($data) {
if (count($data) < 2) { if (count($data) < 2) {
return []; return array();
} }
$headers = array_shift($data); $headers = array_shift($data);
$snapshots = []; $snapshots = array();
// 只取最新的10条 // Only take latest 20 entries
$data = array_slice($data, -10); $data = array_slice($data, -20);
foreach ($data as $row) { foreach ($data as $row) {
$snapshot = []; $snapshot = array();
foreach ($row as $i => $value) { foreach ($row as $i => $value) {
if (isset($headers[$i])) { if (isset($headers[$i])) {
$snapshot[$headers[$i]] = $value; $snapshot[$headers[$i]] = $value;
} }
} }
$snapshots[] = $snapshot;
// Filter out failed snapshots
if (isset($snapshot['statuscode']) && $snapshot['statuscode'] === '200') {
$snapshots[] = $snapshot;
} elseif (!isset($snapshot['statuscode'])) {
// Include if no status code (assume success)
$snapshots[] = $snapshot;
}
} }
return array_reverse($snapshots); return array_reverse($snapshots);
} }
/** /**
* Archive.today 获取数据 * Fetch data from Archive.today
*/ */
private function fetch_from_archive_today($url) { private function fetch_from_archive_today($url) {
// Archive.today 没有官方 API返回空数组 // Archive.today doesn't have official API, return empty array
// 但仍可以触发保存 // But can still trigger save
return array(); return array();
} }
/** /**
* 更新访问统计 * Update access statistics
*/ */
private function update_access_stats($url_hash, $service = 'wenpai') { private function update_access_stats($url_hash, $service = 'wenpai') {
global $wpdb; global $wpdb;
@ -435,7 +545,7 @@ class Archiver_Cache {
} }
/** /**
* 提升缓存级别 * Promote cache level
*/ */
private function promote_cache($url_hash, $service, $new_type) { private function promote_cache($url_hash, $service, $new_type) {
global $wpdb; global $wpdb;
@ -454,12 +564,12 @@ class Archiver_Cache {
} }
/** /**
* 清理过期缓存 * Clean expired cache
*/ */
public function cleanup_expired_cache() { public function cleanup_expired_cache() {
global $wpdb; global $wpdb;
// 保留最近30天的数据即使已过期 // Keep data from last 30 days, even if expired
$cutoff_date = date('Y-m-d H:i:s', time() - (30 * DAY_IN_SECONDS)); $cutoff_date = date('Y-m-d H:i:s', time() - (30 * DAY_IN_SECONDS));
$deleted = $wpdb->query($wpdb->prepare( $deleted = $wpdb->query($wpdb->prepare(
@ -468,14 +578,14 @@ class Archiver_Cache {
current_time('mysql'), $cutoff_date current_time('mysql'), $cutoff_date
)); ));
// 清理孤立的内存缓存 // Clean orphaned memory cache
wp_cache_flush_group('archiver'); wp_cache_flush_group('archiver');
return $deleted; return $deleted;
} }
/** /**
* 获取缓存统计 * Get cache statistics
*/ */
public function get_cache_stats() { public function get_cache_stats() {
global $wpdb; global $wpdb;
@ -483,7 +593,7 @@ class Archiver_Cache {
$stats = $wpdb->get_row( $stats = $wpdb->get_row(
"SELECT "SELECT
COUNT(*) as total_entries, COUNT(*) as total_entries,
SUM(api_calls_saved) as total_api_saves, SUM(CASE WHEN api_calls_saved IS NOT NULL THEN api_calls_saved ELSE 0 END) as total_api_saves,
SUM(CASE WHEN cache_type = 'hot' THEN 1 ELSE 0 END) as hot_entries, SUM(CASE WHEN cache_type = 'hot' THEN 1 ELSE 0 END) as hot_entries,
SUM(CASE WHEN cache_type = 'warm' THEN 1 ELSE 0 END) as warm_entries, SUM(CASE WHEN cache_type = 'warm' THEN 1 ELSE 0 END) as warm_entries,
SUM(CASE WHEN cache_type = 'cold' THEN 1 ELSE 0 END) as cold_entries, SUM(CASE WHEN cache_type = 'cold' THEN 1 ELSE 0 END) as cold_entries,
@ -493,10 +603,10 @@ class Archiver_Cache {
WHERE status = 'active'" WHERE status = 'active'"
); );
// 添加服务级别的统计 // Add service-level statistics
if ($stats) { if ($stats) {
$stats->service_stats = $wpdb->get_results( $stats->service_stats = $wpdb->get_results(
"SELECT service, COUNT(*) as count, SUM(api_calls_saved) as saves "SELECT service, COUNT(*) as count, SUM(CASE WHEN api_calls_saved IS NOT NULL THEN api_calls_saved ELSE 0 END) as saves
FROM {$this->table_name} FROM {$this->table_name}
WHERE status = 'active' WHERE status = 'active'
GROUP BY service" GROUP BY service"
@ -507,7 +617,7 @@ class Archiver_Cache {
} }
/** /**
* 预热缓存 * Preheat cache
*/ */
public function preheat_cache($post_types = null) { public function preheat_cache($post_types = null) {
if (!$post_types) { if (!$post_types) {
@ -531,10 +641,12 @@ class Archiver_Cache {
foreach ($posts as $post_id) { foreach ($posts as $post_id) {
$url = get_permalink($post_id); $url = get_permalink($post_id);
foreach ($enabled_services as $service_id => $enabled) { if ($url) {
if ($enabled) { foreach ($enabled_services as $service_id => $enabled) {
$this->queue_for_update($url, $service_id); if ($enabled) {
$count++; $this->queue_for_update($url, $service_id);
$count++;
}
} }
} }
} }
@ -543,7 +655,7 @@ class Archiver_Cache {
} }
/** /**
* 获取缓存大小 * Get cache size
*/ */
public function get_cache_size() { public function get_cache_size() {
global $wpdb; global $wpdb;
@ -559,20 +671,20 @@ class Archiver_Cache {
} }
/** /**
* 优化缓存表 * Optimize cache table
*/ */
public function optimize_cache_table() { public function optimize_cache_table() {
global $wpdb; global $wpdb;
// 优化表 // Optimize table
$wpdb->query("OPTIMIZE TABLE {$this->table_name}"); $wpdb->query("OPTIMIZE TABLE {$this->table_name}");
// 更新统计信息 // Update statistics
$wpdb->query("ANALYZE TABLE {$this->table_name}"); $wpdb->query("ANALYZE TABLE {$this->table_name}");
} }
/** /**
* 增加存档计数 * Increment archived count
*/ */
private function increment_archived_count() { private function increment_archived_count() {
$count = get_option('archiver_total_archived', 0); $count = get_option('archiver_total_archived', 0);
@ -580,7 +692,7 @@ class Archiver_Cache {
} }
/** /**
* 增加失败计数 * Increment failed count
*/ */
private function increment_failed_count() { private function increment_failed_count() {
$count = get_option('archiver_failed_snapshots', 0); $count = get_option('archiver_failed_snapshots', 0);
@ -588,7 +700,7 @@ class Archiver_Cache {
} }
/** /**
* 获取服务健康状态 * Get service health status
*/ */
public function get_service_health($service = null) { public function get_service_health($service = null) {
global $wpdb; global $wpdb;
@ -599,7 +711,7 @@ class Archiver_Cache {
"SELECT "SELECT
COUNT(*) as total_attempts, COUNT(*) as total_attempts,
SUM(CASE WHEN snapshot_count > 0 THEN 1 ELSE 0 END) as successful, SUM(CASE WHEN snapshot_count > 0 THEN 1 ELSE 0 END) as successful,
AVG(api_calls_saved) as avg_saves AVG(CASE WHEN api_calls_saved IS NOT NULL THEN api_calls_saved ELSE 0 END) as avg_saves
FROM {$this->table_name} FROM {$this->table_name}
WHERE created_at > DATE_SUB(NOW(), INTERVAL 7 DAY)" . $where WHERE created_at > DATE_SUB(NOW(), INTERVAL 7 DAY)" . $where
); );
@ -612,17 +724,19 @@ class Archiver_Cache {
} }
} }
// 注册清理任务 // Register cleanup task
add_action('archiver_cleanup_cache', function() { add_action('archiver_cleanup_cache', function() {
$cache = new Archiver_Cache(); if (class_exists('Archiver_Cache')) {
$cleaned = $cache->cleanup_expired_cache(); $cache = new Archiver_Cache();
$cleaned = $cache->cleanup_expired_cache();
if ($cleaned > 0) { if ($cleaned > 0 && defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Cleaned ' . $cleaned . ' expired cache entries'); error_log('[WP Archiver] Cleaned ' . $cleaned . ' expired cache entries');
} }
// 每周优化一次表 // Optimize table once a week
if (date('w') == 0) { // 周日 if (date('w') == 0) { // Sunday
$cache->optimize_cache_table(); $cache->optimize_cache_table();
}
} }
}); });

View file

@ -0,0 +1,508 @@
<?php
/**
* WP Archiver Dashboard Widget
*/
if (!defined('ABSPATH')) {
exit;
}
class Archiver_Dashboard {
protected $archiver;
public function __construct($archiver) {
$this->archiver = $archiver;
add_action('wp_dashboard_setup', array($this, 'add_dashboard_widget'));
add_action('wp_ajax_archiver_dashboard_trigger', array($this, 'ajax_dashboard_trigger'));
add_action('wp_ajax_archiver_dashboard_stats', array($this, 'ajax_dashboard_stats'));
}
/**
* Add dashboard widget
*/
public function add_dashboard_widget() {
if (!current_user_can('manage_options')) {
return;
}
// Remove the second callback function to cancel configuration options
wp_add_dashboard_widget(
'archiver_dashboard_widget',
__('Archive Status', 'archiver'),
array($this, 'render_dashboard_widget')
// Remove configuration callback
// array($this, 'render_dashboard_widget_config')
);
}
/**
* Render dashboard widget
*/
public function render_dashboard_widget() {
$stats = $this->get_dashboard_stats();
$pending_count = count(get_option('archiver_urls_to_update', array())) +
count(get_option('archiver_background_queue', array()));
// Get pre-calculated display times or timestamps
$last_run_display = get_option('archiver_last_run', '');
$last_run_timestamp = get_option('archiver_last_run_timestamp', 0);
$next_run = wp_next_scheduled('archiver_process_urls');
// Format last run time
if (!empty($last_run_display)) {
$last_run_formatted = $last_run_display;
} elseif ($last_run_timestamp > 0) {
$last_run_formatted = $this->format_timestamp_with_timezone($last_run_timestamp);
} else {
// If we have a string that might be a date
$last_run = get_option('archiver_last_run');
if (!empty($last_run) && ($timestamp = strtotime($last_run)) !== false) {
$last_run_formatted = $this->format_timestamp_with_timezone($timestamp);
} else {
$last_run_formatted = __('Never', 'archiver');
}
}
// Format next run time
$next_run_display = get_option('archiver_next_run_display', '');
if (!empty($next_run_display)) {
$next_run_formatted = $next_run_display;
} elseif ($next_run) {
$next_run_formatted = $this->format_timestamp_with_timezone($next_run);
} else {
$next_run_formatted = __('Not scheduled', 'archiver');
}
?>
<div class="archiver-dashboard-widget">
<div class="archiver-dashboard-stats">
<div class="archiver-stat-item">
<span class="stat-number"><?php echo number_format($stats['total_archived']); ?></span>
<span class="stat-label"><?php _e('Total Archived', 'archiver'); ?></span>
</div>
<div class="archiver-stat-item">
<span class="stat-number <?php echo $pending_count > 0 ? 'has-pending' : ''; ?>"><?php echo number_format($pending_count); ?></span>
<span class="stat-label"><?php _e('Pending', 'archiver'); ?></span>
</div>
<div class="archiver-stat-item">
<span class="stat-number"><?php echo number_format($stats['failed_snapshots']); ?></span>
<span class="stat-label"><?php _e('Failed', 'archiver'); ?></span>
</div>
</div>
<div class="archiver-dashboard-info">
<p>
<strong><?php _e('Last Run:', 'archiver'); ?></strong>
<?php echo esc_html($last_run_formatted); ?>
</p>
<p>
<strong><?php _e('Next Run:', 'archiver'); ?></strong>
<?php echo esc_html($next_run_formatted); ?>
</p>
</div>
<div class="archiver-dashboard-actions">
<div class="action-group">
<input type="url" id="archiver-dashboard-url" placeholder="<?php esc_attr_e('Enter URL to archive...', 'archiver'); ?>" />
<button type="button" class="button button-primary" id="archiver-dashboard-submit">
<?php _e('Archive Now', 'archiver'); ?>
</button>
</div>
<div class="action-group">
<button type="button" class="button" id="archiver-process-queue">
<?php _e('Process Queue', 'archiver'); ?>
</button>
<button type="button" class="button" id="archiver-refresh-stats">
<?php _e('Refresh Stats', 'archiver'); ?>
</button>
</div>
</div>
<div id="archiver-dashboard-status" class="archiver-status" style="display: none;"></div>
<?php if ($pending_count > 0): ?>
<div class="archiver-queue-preview">
<h4><?php _e('Recent Queue Items', 'archiver'); ?></h4>
<div class="queue-items">
<?php
$queue_items = array_merge(
array_slice(get_option('archiver_urls_to_update', array()), 0, 3),
array_slice(get_option('archiver_background_queue', array()), 0, 3)
);
foreach (array_slice($queue_items, 0, 3) as $item):
$url = is_array($item) ? $item['url'] : $item;
?>
<div class="queue-item"><?php echo esc_html($url); ?></div>
<?php endforeach; ?>
<?php if ($pending_count > 3): ?>
<div class="queue-more">
<?php printf(__('... and %d more', 'archiver'), $pending_count - 3); ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
<style>
.archiver-dashboard-widget {
font-size: 13px;
}
.archiver-dashboard-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-bottom: 15px;
}
.archiver-stat-item {
text-align: center;
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
border: 1px solid #e1e4e8;
}
.stat-number {
font-size: 18px;
font-weight: 600;
color: #2271b1;
line-height: 1;
}
.stat-number.has-pending {
color: #d63638;
}
.stat-label {
display: block;
font-size: 11px;
color: #646970;
margin-top: 5px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.archiver-dashboard-info {
background: #fff;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 10px;
margin-bottom: 15px;
}
.archiver-dashboard-info p {
margin: 5px 0;
}
.archiver-dashboard-actions {
margin-bottom: 15px;
}
.action-group {
display: flex;
gap: 5px;
margin-bottom: 8px;
}
.action-group:last-child {
margin-bottom: 0;
}
#archiver-dashboard-url {
flex: 1;
font-size: 12px;
height: 28px;
}
.archiver-dashboard-widget .button {
font-size: 11px;
height: 28px;
line-height: 26px;
padding: 0 10px;
}
.archiver-status {
padding: 8px 10px;
border-radius: 3px;
margin-top: 10px;
font-size: 12px;
}
.archiver-status.success {
background: #d7eddb;
border-left: 4px solid #46b450;
color: #155724;
}
.archiver-status.error {
background: #f8d7da;
border-left: 4px solid #dc3545;
color: #721c24;
}
.archiver-status.info {
background: #cce7ff;
border-left: 4px solid #007cba;
color: #004085;
}
.archiver-queue-preview {
border-top: 1px solid #ddd;
padding-top: 15px;
margin-top: 15px;
}
.archiver-queue-preview h4 {
margin: 0 0 10px;
font-size: 12px;
color: #23282d;
}
.queue-item {
background: #f6f7f7;
padding: 6px 8px;
margin-bottom: 3px;
border-radius: 3px;
font-size: 11px;
word-break: break-all;
color: #50575e;
font-family: Consolas, Monaco, monospace;
}
.queue-more {
text-align: center;
font-style: italic;
color: #646970;
font-size: 11px;
margin-top: 5px;
}
.archiver-dashboard-widget .spinner {
float: none;
margin: 0 5px 0 0;
}
</style>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Archive URL
$('#archiver-dashboard-submit').on('click', function() {
const $button = $(this);
const $status = $('#archiver-dashboard-status');
const url = $('#archiver-dashboard-url').val().trim();
if (!url) {
showStatus('<?php echo esc_js(__('Please enter a valid URL', 'archiver')); ?>', 'error');
return;
}
$button.prop('disabled', true).text('<?php echo esc_js(__('Processing...', 'archiver')); ?>');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'archiver_dashboard_trigger',
url: url,
nonce: '<?php echo wp_create_nonce('archiver_dashboard_nonce'); ?>'
},
success: function(response) {
if (response.success) {
showStatus(response.data.message, 'success');
$('#archiver-dashboard-url').val('');
refreshStats();
} else {
showStatus(response.data.message || '<?php echo esc_js(__('Archive failed', 'archiver')); ?>', 'error');
}
},
error: function() {
showStatus('<?php echo esc_js(__('Request failed', 'archiver')); ?>', 'error');
},
complete: function() {
$button.prop('disabled', false).text('<?php echo esc_js(__('Archive Now', 'archiver')); ?>');
}
});
});
// Process queue
$('#archiver-process-queue').on('click', function() {
const $button = $(this);
$button.prop('disabled', true).text('<?php echo esc_js(__('Processing...', 'archiver')); ?>');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'archiver_dashboard_trigger',
process_queue: true,
nonce: '<?php echo wp_create_nonce('archiver_dashboard_nonce'); ?>'
},
success: function(response) {
if (response.success) {
showStatus(response.data.message, 'success');
refreshStats();
} else {
showStatus(response.data.message || '<?php echo esc_js(__('Process failed', 'archiver')); ?>', 'error');
}
},
error: function() {
showStatus('<?php echo esc_js(__('Request failed', 'archiver')); ?>', 'error');
},
complete: function() {
$button.prop('disabled', false).text('<?php echo esc_js(__('Process Queue', 'archiver')); ?>');
}
});
});
// Refresh stats
$('#archiver-refresh-stats').on('click', function() {
refreshStats();
});
// Enter key support
$('#archiver-dashboard-url').on('keypress', function(e) {
if (e.which === 13) {
$('#archiver-dashboard-submit').trigger('click');
}
});
function showStatus(message, type) {
const $status = $('#archiver-dashboard-status');
$status.removeClass('success error info')
.addClass(type)
.html(message)
.show();
setTimeout(function() {
$status.fadeOut();
}, 5000);
}
function refreshStats() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'archiver_dashboard_stats',
nonce: '<?php echo wp_create_nonce('archiver_dashboard_nonce'); ?>'
},
success: function(response) {
if (response.success) {
location.reload(); // Simple refresh for now
}
}
});
}
});
</script>
<?php
}
/**
* Add new method to handle timestamp timezone issues
*/
private function format_timestamp_with_timezone($timestamp) {
if (!$timestamp) {
return __('Not available', 'archiver');
}
// Get WordPress timezone settings
$timezone_string = get_option('timezone_string');
$gmt_offset = get_option('gmt_offset');
try {
if ($timezone_string) {
// Use timezone string
$timezone = new DateTimeZone($timezone_string);
$datetime = new DateTime('@' . $timestamp);
$datetime->setTimezone($timezone);
return $datetime->format(get_option('date_format') . ' ' . get_option('time_format'));
} else if ($gmt_offset) {
// Use GMT offset
$timestamp += $gmt_offset * HOUR_IN_SECONDS;
return date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $timestamp);
}
} catch (Exception $e) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Date formatting error: ' . $e->getMessage());
}
}
// Default fallback to WordPress localized date function
return date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $timestamp);
}
/**
* Get dashboard statistics
*/
private function get_dashboard_stats() {
return array(
'total_archived' => get_option('archiver_total_archived', 0),
'failed_snapshots' => get_option('archiver_failed_snapshots', 0),
'pending_urls' => count(get_option('archiver_urls_to_update', array())),
'queue_count' => count(get_option('archiver_background_queue', array()))
);
}
/**
* AJAX handler for dashboard trigger
*/
public function ajax_dashboard_trigger() {
check_ajax_referer('archiver_dashboard_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => __('Permission denied', 'archiver')));
}
// Process queue
if (isset($_POST['process_queue'])) {
if ($this->archiver && method_exists($this->archiver, 'process_urls_for_update')) {
$processed = $this->archiver->process_urls_for_update();
wp_send_json_success(array(
'message' => sprintf(__('Started processing %d URLs from queue', 'archiver'), $processed)
));
} else {
wp_send_json_error(array('message' => __('Queue processing not available', 'archiver')));
}
return;
}
// Archive single URL
$url = isset($_POST['url']) ? esc_url_raw($_POST['url']) : '';
if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
wp_send_json_error(array('message' => __('Please enter a valid URL', 'archiver')));
}
// Add to queue with high priority
if ($this->archiver && method_exists($this->archiver, 'trigger_url_snapshot')) {
$this->archiver->trigger_url_snapshot($url);
wp_send_json_success(array(
'message' => sprintf(__('URL added to archive queue: %s', 'archiver'), $url)
));
} else {
wp_send_json_error(array('message' => __('Archive functionality not available', 'archiver')));
}
}
/**
* AJAX handler for dashboard stats
*/
public function ajax_dashboard_stats() {
check_ajax_referer('archiver_dashboard_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => __('Permission denied', 'archiver')));
}
$stats = $this->get_dashboard_stats();
wp_send_json_success($stats);
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
/** /**
* 主要的 Archiver * Main Archiver Class
*/ */
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
@ -26,16 +26,49 @@ class Archiver {
public function __construct($args = array()) { public function __construct($args = array()) {
$this->name = __('Archiver', 'archiver'); $this->name = __('Archiver', 'archiver');
$this->snapshot_max_count = apply_filters('archiver_snapshot_max_count', 10); $this->snapshot_max_count = apply_filters('archiver_snapshot_max_count', 10);
$this->services = ARCHIVER_SERVICES;
// 初始化缓存系统 // Initialize services with fallback
$this->cache = new Archiver_Cache(); $this->services = $this->get_available_services();
// 注册钩子 // Register hooks
add_action('init', array($this, 'setup_cron')); add_action('init', array($this, 'setup_cron'));
add_action('rest_api_init', array($this, 'register_rest_routes')); add_action('rest_api_init', array($this, 'register_rest_routes'));
} }
/**
* Get available services with fallback
*/
private function get_available_services() {
if (defined('ARCHIVER_SERVICES') && is_array(ARCHIVER_SERVICES)) {
return ARCHIVER_SERVICES;
}
// Fallback services if constant is not defined
return array(
'wenpai' => array(
'name' => 'WenPai Archive',
'save_url' => 'https://web.wenpai.net/save/',
'fetch_url' => 'https://web.wenpai.net/cdx/',
'view_url' => 'https://web.wenpai.net/web/',
'enabled' => true
),
'wayback' => array(
'name' => 'Internet Archive',
'save_url' => 'https://web.archive.org/save/',
'fetch_url' => 'https://web.archive.org/cdx/search/cdx',
'view_url' => 'https://web.archive.org/web/',
'enabled' => true
),
'archive_today' => array(
'name' => 'Archive.today',
'save_url' => 'https://archive.today/?run=1&url=',
'fetch_url' => 'https://archive.today/',
'view_url' => 'https://archive.today/',
'enabled' => false
)
);
}
public function get_slug() { public function get_slug() {
return $this->slug; return $this->slug;
} }
@ -48,19 +81,24 @@ class Archiver {
public function init() { public function init() {
$this->set_locale(); $this->set_locale();
// 注册脚本和样式 // Initialize cache system after WordPress is fully loaded
if (class_exists('Archiver_Cache')) {
$this->cache = new Archiver_Cache();
}
// Register scripts and styles
add_action('wp_enqueue_scripts', array($this, 'register_scripts_and_styles'), 5); add_action('wp_enqueue_scripts', array($this, 'register_scripts_and_styles'), 5);
add_action('admin_enqueue_scripts', array($this, 'register_scripts_and_styles'), 5); add_action('admin_enqueue_scripts', array($this, 'register_scripts_and_styles'), 5);
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts')); add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts')); add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
// AJAX 处理 // AJAX handlers
add_action('wp_ajax_archiver_immediate_snapshot', array($this, 'ajax_immediate_snapshot')); add_action('wp_ajax_archiver_immediate_snapshot', array($this, 'ajax_immediate_snapshot'));
add_action('wp_ajax_archiver_check_cache_update', array($this, 'ajax_check_cache_update')); add_action('wp_ajax_archiver_check_cache_update', array($this, 'ajax_check_cache_update'));
add_action('wp_ajax_archiver_get_snapshots', array($this, 'ajax_get_snapshots')); add_action('wp_ajax_archiver_get_snapshots', array($this, 'ajax_get_snapshots'));
if ($this->can_run()) { if ($this->can_run()) {
// 内容钩子 // Content hooks
if (get_option('archiver_auto_archive', true)) { if (get_option('archiver_auto_archive', true)) {
add_action('save_post', array($this, 'trigger_post_snapshot')); add_action('save_post', array($this, 'trigger_post_snapshot'));
add_action('created_term', array($this, 'trigger_term_snapshot'), 10, 3); add_action('created_term', array($this, 'trigger_term_snapshot'), 10, 3);
@ -70,9 +108,15 @@ class Archiver {
add_action('admin_bar_menu', array($this, 'add_admin_bar_links'), 999); add_action('admin_bar_menu', array($this, 'add_admin_bar_links'), 999);
} }
// 后台处理钩子 // Background processing hooks
add_action('archiver_process_background_queue', array($this->cache, 'process_background_queue')); if ($this->cache) {
add_action('archiver_process_background_queue', array($this->cache, 'process_background_queue'));
}
add_action('archiver_fetch_single_url', array($this, 'fetch_single_url_background')); add_action('archiver_fetch_single_url', array($this, 'fetch_single_url_background'));
// Register new hook for priority queue
add_action('archiver_process_priority_queue', array($this, 'process_priority_queue'));
add_action('archiver_trigger_single_service', array($this, 'trigger_single_service_archive'), 10, 2);
} }
public function admin_init() { public function admin_init() {
@ -90,18 +134,77 @@ class Archiver {
} }
public function setup_cron() { public function setup_cron() {
$frequency = get_option('archiver_update_frequency', 'daily'); // Add custom Cron intervals - ensure "hourly" works correctly
if (!wp_next_scheduled('archiver_process_urls')) { add_filter('cron_schedules', array($this, 'add_custom_cron_intervals'));
wp_schedule_event(time(), $frequency, 'archiver_process_urls');
// Get current frequency setting
$frequency = get_option('archiver_update_frequency', 'hourly');
// Check existing scheduled tasks
$timestamp = wp_next_scheduled('archiver_process_urls');
// If no schedule exists or the last schedule time is more than 24 hours ago, reschedule task
$last_schedule_time = get_option('archiver_last_schedule_time', 0);
$schedule_age = time() - $last_schedule_time;
if (!$timestamp || $schedule_age > DAY_IN_SECONDS) {
// Cancel any existing scheduled tasks
if ($timestamp) {
wp_unschedule_event($timestamp, 'archiver_process_urls');
}
// Ensure no duplicate tasks
$this->clear_duplicate_cron_tasks('archiver_process_urls');
// Create new scheduled task, add 1-60 seconds random delay
$offset = mt_rand(1, 60);
wp_schedule_event(time() + $offset, $frequency, 'archiver_process_urls');
// Record scheduling time
update_option('archiver_last_schedule_time', time());
// Record next run time for immediate display
$this->update_next_run_display_time();
// Debug log
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Rescheduled process_urls task with frequency: ' . $frequency);
}
} }
add_action('archiver_process_urls', array($this, 'process_urls_for_update')); add_action('archiver_process_urls', array($this, 'process_urls_for_update'));
} }
/**
* Add custom Cron intervals - ensure "hourly" and other intervals work as expected
*/
public function add_custom_cron_intervals($schedules) {
// Add 15-minute interval for high-frequency scenarios
$schedules['minutes_15'] = array(
'interval' => 15 * MINUTE_IN_SECONDS,
'display' => __('Every 15 Minutes', 'archiver')
);
// Add 30-minute interval for medium-frequency scenarios
$schedules['minutes_30'] = array(
'interval' => 30 * MINUTE_IN_SECONDS,
'display' => __('Every 30 Minutes', 'archiver')
);
// Ensure hourly interval exists and is clearly defined
$schedules['exact_hourly'] = array(
'interval' => HOUR_IN_SECONDS,
'display' => __('Exactly Every Hour', 'archiver')
);
return $schedules;
}
public function can_run() { public function can_run() {
return apply_filters('archiver_can_run', __return_true()); return apply_filters('archiver_can_run', __return_true());
} }
// Meta Box 相关方法 // Meta Box related methods
public function add_post_meta_box() { public function add_post_meta_box() {
$post_types = get_option('archiver_post_types', array('post', 'page')); $post_types = get_option('archiver_post_types', array('post', 'page'));
add_meta_box( add_meta_box(
@ -122,7 +225,15 @@ class Archiver {
} }
public function output_term_meta_box() { public function output_term_meta_box() {
if (!isset($_GET['tag_ID'])) {
return;
}
$term = get_term($_GET['tag_ID']); $term = get_term($_GET['tag_ID']);
if (is_wp_error($term)) {
return;
}
$url = get_term_link($term); $url = get_term_link($term);
if (!is_wp_error($url)) { if (!is_wp_error($url)) {
$this->current_permalink = $url; $this->current_permalink = $url;
@ -169,7 +280,7 @@ class Archiver {
<div class="archiver-service-tabs"> <div class="archiver-service-tabs">
<?php foreach ($enabled_services as $service_id => $enabled) : <?php foreach ($enabled_services as $service_id => $enabled) :
if (!$enabled) continue; if (!$enabled) continue;
$service = $this->services[$service_id]; $service = isset($this->services[$service_id]) ? $this->services[$service_id] : array('name' => ucfirst($service_id));
?> ?>
<button class="archiver-service-tab <?php echo $service_id === $primary_service ? 'active' : ''; ?>" <button class="archiver-service-tab <?php echo $service_id === $primary_service ? 'active' : ''; ?>"
data-service="<?php echo esc_attr($service_id); ?>"> data-service="<?php echo esc_attr($service_id); ?>">
@ -187,7 +298,6 @@ class Archiver {
<div class="archiver-actions"> <div class="archiver-actions">
<button id="archiver-immediate-snapshot" class="button button-secondary"> <button id="archiver-immediate-snapshot" class="button button-secondary">
<span class="dashicons dashicons-backup"></span>
<?php _e('Archive Now', 'archiver'); ?> <?php _e('Archive Now', 'archiver'); ?>
</button> </button>
<span id="archiver-status" style="margin-left: 10px; display: none;"></span> <span id="archiver-status" style="margin-left: 10px; display: none;"></span>
@ -195,7 +305,7 @@ class Archiver {
<?php <?php
} }
// AJAX 处理方法 // AJAX handler methods
public function ajax_get_snapshots() { public function ajax_get_snapshots() {
check_ajax_referer('archiver_immediate_snapshot', '_ajax_nonce'); check_ajax_referer('archiver_immediate_snapshot', '_ajax_nonce');
@ -206,7 +316,15 @@ class Archiver {
wp_send_json_error(['message' => __('Invalid URL', 'archiver')]); wp_send_json_error(['message' => __('Invalid URL', 'archiver')]);
} }
$snapshots = $this->cache->get_snapshots($url, $service); // Debug logging
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Getting snapshots for URL: ' . $url . ' Service: ' . $service);
}
$snapshots = array();
if ($this->cache && method_exists($this->cache, 'get_snapshots')) {
$snapshots = $this->cache->get_snapshots($url, $service);
}
if (!empty($snapshots)) { if (!empty($snapshots)) {
$html = $this->format_snapshots_html($snapshots, $service); $html = $this->format_snapshots_html($snapshots, $service);
@ -237,29 +355,35 @@ class Archiver {
wp_send_json_error(['message' => __('Invalid URL.', 'archiver')], 400); wp_send_json_error(['message' => __('Invalid URL.', 'archiver')], 400);
} }
// 触发快照到所有启用的服务 // Debug logging
$enabled_services = get_option('archiver_services', array('wayback' => true)); if (defined('WP_DEBUG') && WP_DEBUG) {
$triggered = 0; error_log('[WP Archiver] Triggering snapshot for URL: ' . $url . ' Service: ' . $service);
}
foreach ($enabled_services as $service_id => $enabled) { // Add URL to high-priority queue
if ($enabled && (!$service || $service === $service_id)) { if ($this->cache && method_exists($this->cache, 'queue_for_update')) {
$result = $this->trigger_archive_service($url, $service_id); if ($service) {
if ($result) { $this->cache->queue_for_update($url, $service, true);
$triggered++; } else {
// Add to queue for all enabled services
$enabled_services = get_option('archiver_services', array('wenpai' => true));
foreach ($enabled_services as $service_id => $enabled) {
if ($enabled) {
$this->cache->queue_for_update($url, $service_id, true);
}
} }
// 强制刷新缓存
$this->cache->queue_for_update($url, $service_id, true);
} }
} }
if ($triggered > 0) { // Schedule an immediate event to process high-priority queue
wp_send_json_success([ if (!wp_next_scheduled('archiver_process_priority_queue')) {
'message' => sprintf(__('Snapshot request submitted to %d service(s).', 'archiver'), $triggered), wp_schedule_single_event(time() + 5, 'archiver_process_priority_queue');
'refresh' => true
]);
} else {
wp_send_json_error(['message' => __('Failed to trigger snapshot.', 'archiver')]);
} }
wp_send_json_success([
'message' => __('Snapshot request submitted and will be processed shortly.', 'archiver'),
'refresh' => true
]);
} }
public function ajax_check_cache_update() { public function ajax_check_cache_update() {
@ -272,7 +396,11 @@ class Archiver {
wp_send_json_error(); wp_send_json_error();
} }
$snapshots = $this->cache->get_snapshots($url, $service); $snapshots = array();
if ($this->cache && method_exists($this->cache, 'get_snapshots')) {
$snapshots = $this->cache->get_snapshots($url, $service, true); // Force refresh
}
wp_send_json_success([ wp_send_json_success([
'has_update' => !empty($snapshots), 'has_update' => !empty($snapshots),
'count' => count($snapshots), 'count' => count($snapshots),
@ -280,7 +408,7 @@ class Archiver {
]); ]);
} }
private function format_snapshots_html($snapshots, $service = 'wayback') { private function format_snapshots_html($snapshots, $service = 'wenpai') {
if (empty($snapshots)) { if (empty($snapshots)) {
return ''; return '';
} }
@ -288,17 +416,28 @@ class Archiver {
$html = '<ul class="archiver-snapshot-list">'; $html = '<ul class="archiver-snapshot-list">';
$date_format = get_option('date_format'); $date_format = get_option('date_format');
$time_format = get_option('time_format'); $time_format = get_option('time_format');
$service_config = $this->services[$service] ?? $this->services['wenpai']; $service_config = isset($this->services[$service]) ? $this->services[$service] : $this->services['wenpai'];
foreach (array_slice($snapshots, 0, $this->snapshot_max_count) as $snapshot) { foreach (array_slice($snapshots, 0, $this->snapshot_max_count) as $snapshot) {
$timestamp = isset($snapshot['timestamp']) ? $snapshot['timestamp'] : ''; $timestamp = isset($snapshot['timestamp']) ? $snapshot['timestamp'] : '';
$original = isset($snapshot['original']) ? $snapshot['original'] : ''; $original = isset($snapshot['original']) ? $snapshot['original'] : '';
if ($timestamp && $original) { if ($timestamp && $original) {
$date_time = date('Y.m.d H:i', strtotime($timestamp)); // Handle different timestamp formats
$adjusted_date = get_date_from_gmt($date_time); if (strlen($timestamp) === 14) {
// Format: YYYYMMDDHHMMSS
$date_time = substr($timestamp, 0, 4) . '-' .
substr($timestamp, 4, 2) . '-' .
substr($timestamp, 6, 2) . ' ' .
substr($timestamp, 8, 2) . ':' .
substr($timestamp, 10, 2) . ':' .
substr($timestamp, 12, 2);
} else {
$date_time = $timestamp;
}
$snapshot_url = $service_config['view_url'] . $timestamp . '/' . $original; $snapshot_url = $service_config['view_url'] . $timestamp . '/' . $original;
$formatted_date = date_i18n($date_format . ' @ ' . $time_format, strtotime($adjusted_date)); $formatted_date = date_i18n($date_format . ' @ ' . $time_format, strtotime($date_time));
$html .= sprintf( $html .= sprintf(
'<li><a href="%s" target="_blank" rel="noopener noreferrer">%s</a></li>', '<li><a href="%s" target="_blank" rel="noopener noreferrer">%s</a></li>',
@ -316,7 +455,7 @@ class Archiver {
$html .= sprintf( $html .= sprintf(
'<a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="dashicons dashicons-external"></span></a>', '<a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="dashicons dashicons-external"></span></a>',
esc_url($view_all_url), esc_url($view_all_url),
__('See all snapshots', 'archiver') __('View all snapshots', 'archiver')
); );
$html .= '</p>'; $html .= '</p>';
@ -359,7 +498,7 @@ class Archiver {
]); ]);
// Add service submenu // Add service submenu
$enabled_services = get_option('archiver_services', array('wayback' => true)); $enabled_services = get_option('archiver_services', array('wenpai' => true));
foreach ($enabled_services as $service_id => $enabled) { foreach ($enabled_services as $service_id => $enabled) {
if ($enabled && isset($this->services[$service_id])) { if ($enabled && isset($this->services[$service_id])) {
$service = $this->services[$service_id]; $service = $this->services[$service_id];
@ -374,7 +513,7 @@ class Archiver {
} }
} }
// 获取当前页面 URL // Get current page URL
public function get_current_permalink() { public function get_current_permalink() {
if (empty($this->current_permalink)) { if (empty($this->current_permalink)) {
if (is_admin()) { if (is_admin()) {
@ -433,7 +572,7 @@ class Archiver {
return $permalink; return $permalink;
} }
// 脚本和样式 // Scripts and styles
public function register_scripts_and_styles() { public function register_scripts_and_styles() {
wp_register_script( wp_register_script(
'archiver', 'archiver',
@ -450,7 +589,7 @@ class Archiver {
ARCHIVER_VERSION ARCHIVER_VERSION
); );
// 添加管理员 nonce // Add admin nonce
$admin_nonce = is_admin() ? wp_create_nonce('archiver_admin_nonce') : ''; $admin_nonce = is_admin() ? wp_create_nonce('archiver_admin_nonce') : '';
wp_localize_script('archiver', 'archiver', array( wp_localize_script('archiver', 'archiver', array(
@ -469,7 +608,7 @@ class Archiver {
'success' => __('Snapshot triggered successfully!', 'archiver'), 'success' => __('Snapshot triggered successfully!', 'archiver'),
'error' => __('Failed to trigger snapshot.', 'archiver'), 'error' => __('Failed to trigger snapshot.', 'archiver'),
'no_snapshots' => __('No archives yet.', 'archiver'), 'no_snapshots' => __('No archives yet.', 'archiver'),
'view_all' => __('See all snapshots', 'archiver'), 'view_all' => __('View all snapshots', 'archiver'),
'checking' => __('Checking...', 'archiver'), 'checking' => __('Checking...', 'archiver'),
'online' => __('Online', 'archiver'), 'online' => __('Online', 'archiver'),
'offline' => __('Offline', 'archiver'), 'offline' => __('Offline', 'archiver'),
@ -493,7 +632,8 @@ class Archiver {
'term.php', 'term.php',
'profile.php', 'profile.php',
'user-edit.php', 'user-edit.php',
'tools_page_archiver-settings' 'tools_page_archiver-settings',
'index.php' // Dashboard
); );
if (in_array($hook, $allowed_hooks)) { if (in_array($hook, $allowed_hooks)) {
@ -545,18 +685,25 @@ class Archiver {
$url = $request->get_param('url'); $url = $request->get_param('url');
$service = $request->get_param('service'); $service = $request->get_param('service');
if ($service) { if ($this->cache && method_exists($this->cache, 'queue_for_update')) {
$this->cache->queue_for_update($url, $service, true); if ($service) {
} else { $this->cache->queue_for_update($url, $service, true);
// Queue for all enabled services } else {
$enabled_services = get_option('archiver_services', array('wayback' => true)); // Queue for all enabled services
foreach ($enabled_services as $service_id => $enabled) { $enabled_services = get_option('archiver_services', array('wenpai' => true));
if ($enabled) { foreach ($enabled_services as $service_id => $enabled) {
$this->cache->queue_for_update($url, $service_id, true); if ($enabled) {
$this->cache->queue_for_update($url, $service_id, true);
}
} }
} }
} }
// Schedule processing of high-priority queue
if (!wp_next_scheduled('archiver_process_priority_queue')) {
wp_schedule_single_event(time() + 5, 'archiver_process_priority_queue');
}
return new WP_REST_Response(array( return new WP_REST_Response(array(
'success' => true, 'success' => true,
'message' => __('Snapshot request recorded.', 'archiver') 'message' => __('Snapshot request recorded.', 'archiver')
@ -567,7 +714,10 @@ class Archiver {
$url = $request->get_param('url'); $url = $request->get_param('url');
$service = $request->get_param('service'); $service = $request->get_param('service');
$snapshots = $this->cache->get_snapshots($url, $service); $snapshots = array();
if ($this->cache && method_exists($this->cache, 'get_snapshots')) {
$snapshots = $this->cache->get_snapshots($url, $service);
}
return new WP_REST_Response(array( return new WP_REST_Response(array(
'success' => true, 'success' => true,
@ -576,7 +726,7 @@ class Archiver {
), 200); ), 200);
} }
// 触发快照 // Trigger snapshots - modified to async mode
public function trigger_post_snapshot($post_id) { public function trigger_post_snapshot($post_id) {
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) { if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
return; return;
@ -608,27 +758,131 @@ class Archiver {
$this->trigger_url_snapshot($url); $this->trigger_url_snapshot($url);
} }
/**
* Optimized URL snapshot trigger method - changed to use async queue
*/
public function trigger_url_snapshot($url) { public function trigger_url_snapshot($url) {
if (empty($url)) { if (empty($url)) {
return; return;
} }
// 如果启用了立即存档,直接触发 // Create a high-priority queue item
if (get_option('archiver_archive_on_publish', true)) { $priority = get_option('archiver_archive_on_publish', true) ? 'high' : 'normal';
// Add to queue regardless of immediate archiving setting
if ($this->cache && method_exists($this->cache, 'queue_for_update')) {
// Add to cache queue
$enabled_services = get_option('archiver_services', array('wenpai' => true)); $enabled_services = get_option('archiver_services', array('wenpai' => true));
foreach ($enabled_services as $service_id => $enabled) { foreach ($enabled_services as $service_id => $enabled) {
if ($enabled) { if ($enabled) {
$this->trigger_archive_service($url, $service_id); $this->cache->queue_for_update($url, $service_id, ($priority === 'high'));
} }
} }
} else {
// Fall back to simple queue if cache class unavailable
$existing = get_option('archiver_urls_to_update', array());
if (!is_array($existing)) {
$existing = array();
}
$existing[] = array(
'url' => $url,
'priority' => $priority,
'added' => time()
);
update_option('archiver_urls_to_update', array_unique($existing));
}
// If immediate archiving is enabled, schedule a near-term single event to process the high-priority queue
if ($priority === 'high' && !wp_next_scheduled('archiver_process_priority_queue')) {
wp_schedule_single_event(time() + 5, 'archiver_process_priority_queue');
}
}
/**
* Process high-priority queue
*/
public function process_priority_queue() {
// First get the background queue
$background_queue = get_option('archiver_background_queue', array());
if (!is_array($background_queue)) {
$background_queue = array();
}
// Find high-priority items added within the last 10 minutes
$priority_items = array();
$regular_items = array();
$current_time = time();
$cutoff_time = $current_time - (10 * MINUTE_IN_SECONDS);
foreach ($background_queue as $item) {
// Check if it's an array and has an 'added' field
if (is_array($item) && isset($item['added']) && $item['added'] > $cutoff_time) {
$priority_items[] = $item;
} else {
$regular_items[] = $item;
}
} }
// 添加到更新队列 // Process only up to 5 high-priority items
$this->cache->queue_for_update($url); $batch_size = min(5, count($priority_items));
if ($batch_size === 0) {
return; // No high-priority items to process
}
// Remove items to be processed from the queue
$batch = array_slice($priority_items, 0, $batch_size);
$remaining_priority_items = array_slice($priority_items, $batch_size);
// Update queue
update_option('archiver_background_queue', array_merge($regular_items, $remaining_priority_items));
// Process high-priority items
foreach ($batch as $item) {
if (is_array($item)) {
$url = isset($item['url']) ? $item['url'] : (is_string($item) ? $item : '');
$service = isset($item['service']) ? $item['service'] : null;
if (!empty($url)) {
// Process archive request asynchronously
$this->schedule_nonblocking_archive($url, $service);
}
} else if (is_string($item)) {
// Handle old format queue items
$this->schedule_nonblocking_archive($item);
}
}
// If more high-priority items remain, schedule another processing run
if (count($remaining_priority_items) > 0) {
wp_schedule_single_event(time() + 30, 'archiver_process_priority_queue');
}
} }
private function trigger_archive_service($url, $service = 'wenpai') { /**
* Schedule non-blocking archive request
*/
private function schedule_nonblocking_archive($url, $service = null) {
$enabled_services = get_option('archiver_services', array('wenpai' => true));
foreach ($enabled_services as $service_id => $enabled) {
if ($enabled && (!$service || $service === $service_id)) {
// Register separate events for each service to avoid processing multiple services in the same request
if (!wp_next_scheduled('archiver_trigger_single_service', array($url, $service_id))) {
wp_schedule_single_event(time() + rand(5, 15), 'archiver_trigger_single_service', array($url, $service_id));
}
}
}
}
/**
* Trigger single service archive - executed in a separate WP-Cron request
*/
public function trigger_single_service_archive($url, $service) {
if (!isset($this->services[$service])) { if (!isset($this->services[$service])) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Service not found: ' . $service);
}
return false; return false;
} }
@ -636,57 +890,227 @@ class Archiver {
$save_url = $service_config['save_url'] . urlencode($url); $save_url = $service_config['save_url'] . urlencode($url);
$response = wp_remote_get($save_url, array( $response = wp_remote_get($save_url, array(
'timeout' => 10, 'timeout' => 15,
'sslverify' => true, 'sslverify' => ($service !== 'wenpai'), // WenPai might use self-signed certificates
'headers' => array( 'headers' => array(
'User-Agent' => 'WP-Archiver/' . ARCHIVER_VERSION 'User-Agent' => 'WP-Archiver/' . ARCHIVER_VERSION . ' (WordPress/' . get_bloginfo('version') . ')'
) )
)); ));
return !is_wp_error($response) && in_array(wp_remote_retrieve_response_code($response), array(200, 201, 202)); $success = !is_wp_error($response) && in_array(wp_remote_retrieve_response_code($response), array(200, 201, 202));
// Debug logging
if (defined('WP_DEBUG') && WP_DEBUG) {
if ($success) {
error_log('[WP Archiver] Successfully triggered ' . $service . ' for: ' . $url);
} else {
$error_msg = is_wp_error($response) ? $response->get_error_message() : 'HTTP ' . wp_remote_retrieve_response_code($response);
error_log('[WP Archiver] Failed to trigger ' . $service . ' for: ' . $url . ' - ' . $error_msg);
}
}
// Update cache
if ($success && $this->cache && method_exists($this->cache, 'fetch_and_cache_snapshots')) {
// Wait a moment before refreshing the cache to give the archive service time to process
wp_schedule_single_event(time() + 60, 'archiver_fetch_single_url', array($url));
}
return $success;
} }
// 处理URL更新 /**
* Old synchronous archive call method - kept for compatibility but no longer used directly
*/
private function trigger_archive_service($url, $service = 'wenpai') {
if (!isset($this->services[$service])) {
return false;
}
// Convert this operation to a non-blocking call
if (!wp_next_scheduled('archiver_trigger_single_service', array($url, $service))) {
wp_schedule_single_event(time() + 1, 'archiver_trigger_single_service', array($url, $service));
}
return true;
}
// Process URL updates
public function process_urls_for_update() { public function process_urls_for_update() {
$urls = get_option('archiver_urls_to_update', array()); $urls = get_option('archiver_urls_to_update', array());
if (empty($urls)) { if (empty($urls)) {
$this->update_run_times();
return 0; return 0;
} }
$batch_size = apply_filters('archiver_batch_size', 5); $batch_size = get_option('archiver_batch_size', 10);
$batch = array_splice($urls, 0, $batch_size); $batch = array_splice($urls, 0, $batch_size);
foreach ($batch as $url) { foreach ($batch as $url) {
if (is_array($url) && isset($url['url'])) {
$url = $url['url'];
}
wp_schedule_single_event(time() + rand(5, 30), 'archiver_fetch_single_url', array($url)); wp_schedule_single_event(time() + rand(5, 30), 'archiver_fetch_single_url', array($url));
} }
update_option('archiver_urls_to_update', $urls); update_option('archiver_urls_to_update', $urls);
update_option('archiver_last_run', current_time('mysql'));
// Update run times
$this->update_run_times();
return count($batch); return count($batch);
} }
/**
* Update run time records - use UTC timestamps for internal storage
*/
private function update_run_times() {
// Record last run time using UTC time
$now_utc = time();
update_option('archiver_last_run_timestamp', $now_utc);
// Also store a formatted version using site's timezone for direct display
update_option('archiver_last_run', $this->get_formatted_schedule_time($now_utc));
// Calculate and record next run time
$next_run = wp_next_scheduled('archiver_process_urls');
if ($next_run) {
update_option('archiver_next_run_timestamp', $next_run);
update_option('archiver_next_run_display', $this->get_formatted_schedule_time($next_run));
}
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Run times updated. Last run: ' . date('Y-m-d H:i:s', $now_utc) . ', Next run timestamp: ' . ($next_run ?: 'none'));
}
}
public function fetch_single_url_background($url) { public function fetch_single_url_background($url) {
$enabled_services = get_option('archiver_services', array('wenpai' => true)); $enabled_services = get_option('archiver_services', array('wenpai' => true));
foreach ($enabled_services as $service_id => $enabled) { foreach ($enabled_services as $service_id => $enabled) {
if ($enabled) { if ($enabled) {
// Fetch and cache snapshots // Fetch and cache snapshots
$this->cache->fetch_and_cache_snapshots($url, $service_id); if ($this->cache && method_exists($this->cache, 'fetch_and_cache_snapshots')) {
$this->cache->fetch_and_cache_snapshots($url, $service_id);
// Also trigger new snapshot }
$this->trigger_archive_service($url, $service_id);
} }
} }
} }
// 重新安排 Cron 任务 /**
* Fixed Cron task rescheduling method
*/
public function reschedule_cron_task($frequency) { public function reschedule_cron_task($frequency) {
// Convert to exact interval if hourly is specified
if ($frequency === 'hourly') {
$frequency = 'exact_hourly';
}
// Ensure frequency is valid
$valid_frequencies = array('minutes_15', 'minutes_30', 'exact_hourly', 'hourly', 'twicedaily', 'daily', 'weekly');
if (!in_array($frequency, $valid_frequencies)) {
$frequency = 'hourly'; // Default to hourly
}
// Cancel all existing tasks
$timestamp = wp_next_scheduled('archiver_process_urls'); $timestamp = wp_next_scheduled('archiver_process_urls');
if ($timestamp) { if ($timestamp) {
wp_unschedule_event($timestamp, 'archiver_process_urls'); wp_unschedule_event($timestamp, 'archiver_process_urls');
} }
wp_schedule_event(time(), $frequency, 'archiver_process_urls'); // Ensure any duplicate tasks are cleaned up
$this->clear_duplicate_cron_tasks('archiver_process_urls');
// Create new task, add 1-60 seconds random delay
$offset = mt_rand(1, 60);
wp_schedule_event(time() + $offset, $frequency, 'archiver_process_urls');
// Record scheduling time
update_option('archiver_last_schedule_time', time());
// Update displayed next run time to immediately update UI
$this->update_next_run_display_time();
// Debug log
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Cron task rescheduled with frequency: ' . $frequency);
}
}
/**
* Update next run display time
*/
private function update_next_run_display_time() {
$next_run = wp_next_scheduled('archiver_process_urls');
if ($next_run) {
// Save original timestamp and formatted display time
update_option('archiver_next_run_timestamp', $next_run);
update_option('archiver_next_run_display', $this->get_formatted_schedule_time($next_run));
} else {
delete_option('archiver_next_run_timestamp');
delete_option('archiver_next_run_display');
}
}
/**
* Clear duplicate Cron tasks
*/
private function clear_duplicate_cron_tasks($hook) {
$crons = _get_cron_array();
$found = false;
if (empty($crons)) {
return false;
}
foreach ($crons as $timestamp => $cron) {
if (isset($cron[$hook])) {
foreach ($cron[$hook] as $key => $event) {
if ($found) {
// Already found one event, delete other duplicates
wp_unschedule_event($timestamp, $hook, $event['args']);
} else {
// First time finding an event
$found = true;
}
}
}
}
return $found;
}
/**
* Get formatted schedule time (fix timezone issues)
*/
public function get_formatted_schedule_time($timestamp) {
if (!$timestamp) {
return __('Not scheduled', 'archiver');
}
// Get WordPress timezone settings
$timezone_string = get_option('timezone_string');
$gmt_offset = get_option('gmt_offset');
try {
if ($timezone_string) {
// Use timezone string
$timezone = new DateTimeZone($timezone_string);
$datetime = new DateTime('@' . $timestamp); // Create GMT time using @ symbol
$datetime->setTimezone($timezone); // Convert to local timezone
return $datetime->format(get_option('date_format') . ' ' . get_option('time_format'));
} else if (!empty($gmt_offset)) {
// Use GMT offset
$local_timestamp = $timestamp + ($gmt_offset * HOUR_IN_SECONDS);
return date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $local_timestamp);
}
} catch (Exception $e) {
// Log debug info on error
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] Time formatting error: ' . $e->getMessage());
}
}
// Default fallback
return date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $timestamp);
} }
} }

View file

@ -1,430 +0,0 @@
/**
* WP Archiver 前端脚本
*/
(function($) {
'use strict';
const Archiver = {
config: {
checkInterval: 5000,
maxChecks: 12,
fadeInDuration: 300,
cachePrefix: 'archiver_cache_'
},
init: function() {
$(document).ready(() => {
this.initMetabox();
this.initAdminBar();
this.initAdminPage();
this.initLazyLoading();
});
},
/**
* 初始化元框
*/
initMetabox: function() {
const $container = $('#archiver-snapshots');
if (!$container.length) return;
const url = $container.data('url') || $('#archiver-url').val();
if (!url) return;
// 延迟加载快照
this.loadSnapshots(url, $container);
// 立即存档按钮
$('#archiver-immediate-snapshot').on('click', (e) => {
e.preventDefault();
this.triggerSnapshot(url);
});
},
/**
* 初始化管理栏
*/
initAdminBar: function() {
const $trigger = $('#wp-admin-bar-archiver-trigger a');
if (!$trigger.length) return;
// 延迟加载快照计数
const $countItem = $('#wp-admin-bar-archiver-snapshots');
if ($countItem.length && archiver.url) {
this.updateAdminBarCount(archiver.url);
}
// 触发快照
$trigger.on('click', (e) => {
e.preventDefault();
this.triggerAdminBarSnapshot();
});
},
/**
* 初始化管理页面
*/
initAdminPage: function() {
// 标签切换
$('.nav-tab').on('click', function(e) {
e.preventDefault();
const $tab = $(this);
const tabId = $tab.data('tab');
$('.nav-tab').removeClass('nav-tab-active');
$tab.addClass('nav-tab-active');
$('.archiver-tab-content').hide();
$('#' + tabId).fadeIn(300);
// 保存用户偏好
if (typeof(Storage) !== "undefined") {
localStorage.setItem('archiver_active_tab', tabId);
}
});
// 恢复上次的标签
const savedTab = localStorage.getItem('archiver_active_tab');
if (savedTab) {
$(`.nav-tab[data-tab="${savedTab}"]`).trigger('click');
}
},
/**
* 延迟加载
*/
initLazyLoading: function() {
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const $element = $(entry.target);
const url = $element.data('url');
if (url && !$element.data('loaded')) {
this.loadSnapshots(url, $element);
$element.data('loaded', true);
}
}
});
});
$('.archiver-lazy').each(function() {
observer.observe(this);
});
}
},
/**
* 加载快照
*/
loadSnapshots: function(url, $container) {
// 检查本地缓存
const cached = this.getCache(url);
if (cached) {
this.displaySnapshots(cached, $container);
// 后台检查更新
this.checkForUpdates(url, $container);
return;
}
// 显示加载状态
this.showLoading($container);
// 从服务器获取
$.ajax({
url: archiver.ajax_url,
type: 'POST',
data: {
action: 'archiver_get_snapshots',
_ajax_nonce: archiver.ajax_nonce,
url: url
},
success: (response) => {
if (response.success) {
this.setCache(url, response.data);
this.displaySnapshots(response.data, $container);
} else {
this.showError($container, response.data.message);
}
},
error: () => {
this.showError($container, archiver.i18n.error);
}
});
},
/**
* 显示快照
*/
displaySnapshots: function(data, $container) {
if (!data.html) {
$container.html('<p>' + archiver.i18n.no_snapshots + '</p>');
return;
}
$container.hide().html(data.html).fadeIn(this.config.fadeInDuration);
// 添加动画
$container.find('li').each(function(index) {
$(this).css({
opacity: 0,
transform: 'translateY(10px)'
}).delay(index * 50).animate({
opacity: 1,
transform: 'translateY(0)'
}, 300);
});
},
/**
* 触发快照
*/
triggerSnapshot: function(url) {
const $button = $('#archiver-immediate-snapshot');
const $status = $('#archiver-status');
$button.prop('disabled', true).addClass('updating-message');
$status.show().removeClass('error success')
.html('<span class="spinner is-active"></span> ' + archiver.i18n.triggering);
$.ajax({
url: archiver.ajax_url,
type: 'POST',
data: {
action: 'archiver_immediate_snapshot',
_ajax_nonce: archiver.ajax_nonce,
url: url
},
success: (response) => {
if (response.success) {
$status.removeClass('error').addClass('success')
.html('<span class="dashicons dashicons-yes"></span> ' + response.data.message);
// 清除缓存并开始轮询
this.clearCache(url);
if (response.data.refresh) {
this.startPolling(url);
}
} else {
$status.removeClass('success').addClass('error')
.html('<span class="dashicons dashicons-warning"></span> ' + response.data.message);
}
},
error: () => {
$status.removeClass('success').addClass('error')
.html('<span class="dashicons dashicons-warning"></span> ' + archiver.i18n.error);
},
complete: () => {
$button.prop('disabled', false).removeClass('updating-message');
setTimeout(() => {
$status.fadeOut();
}, 5000);
}
});
},
/**
* 管理栏触发快照
*/
triggerAdminBarSnapshot: function() {
const $item = $('#wp-admin-bar-archiver');
$item.addClass('archiver-active');
$.ajax({
url: archiver.rest_url + 'trigger-snapshot',
method: 'POST',
beforeSend: (xhr) => {
xhr.setRequestHeader('X-WP-Nonce', archiver.nonce);
},
data: {
url: archiver.url
},
success: (response) => {
$item.removeClass('archiver-active');
if (response.success) {
$item.addClass('archiver-success');
this.clearCache(archiver.url);
this.updateAdminBarCount(archiver.url);
} else {
$item.addClass('archiver-failure');
}
},
error: () => {
$item.removeClass('archiver-active').addClass('archiver-failure');
},
complete: () => {
setTimeout(() => {
$item.removeClass('archiver-success archiver-failure');
}, 2000);
}
});
},
/**
* 更新管理栏计数
*/
updateAdminBarCount: function(url) {
const $countItem = $('#wp-admin-bar-archiver-snapshots .ab-label');
if (!$countItem.length) return;
$.ajax({
url: archiver.ajax_url,
type: 'POST',
data: {
action: 'archiver_get_snapshots',
_ajax_nonce: archiver.ajax_nonce,
url: url
},
success: (response) => {
if (response.success && response.data.count !== undefined) {
const count = response.data.count >= 10 ? '10+' : response.data.count;
$countItem.text(archiver.i18n.view_all + ' (' + count + ')');
}
}
});
},
/**
* 检查更新
*/
checkForUpdates: function(url, $container) {
$.ajax({
url: archiver.ajax_url,
type: 'POST',
data: {
action: 'archiver_check_cache_update',
_ajax_nonce: archiver.ajax_nonce,
url: url
},
success: (response) => {
if (response.success && response.data.has_update) {
this.clearCache(url);
this.displaySnapshots(response.data, $container);
}
}
});
},
/**
* 开始轮询
*/
startPolling: function(url) {
let checkCount = 0;
const $container = $('#archiver-snapshots');
const interval = setInterval(() => {
checkCount++;
if (checkCount > this.config.maxChecks) {
clearInterval(interval);
return;
}
this.checkForUpdates(url, $container);
}, this.config.checkInterval);
},
/**
* 显示加载状态
*/
showLoading: function($container) {
const loadingHtml = `
<div class="archiver-loading">
<span class="spinner is-active"></span>
${archiver.i18n.loading}
</div>
`;
$container.html(loadingHtml);
},
/**
* 显示错误
*/
showError: function($container, message) {
$container.html('<p class="archiver-error">' + message + '</p>');
},
/**
* 缓存管理
*/
getCache: function(url) {
if (!this.isStorageAvailable()) return null;
try {
const key = this.config.cachePrefix + this.hashCode(url);
const cached = sessionStorage.getItem(key);
if (cached) {
const data = JSON.parse(cached);
// 5分钟缓存
if (Date.now() - data.timestamp < 300000) {
return data.content;
}
}
} catch (e) {
console.warn('Cache read error:', e);
}
return null;
},
setCache: function(url, data) {
if (!this.isStorageAvailable()) return;
try {
const key = this.config.cachePrefix + this.hashCode(url);
const cacheData = {
content: data,
timestamp: Date.now()
};
sessionStorage.setItem(key, JSON.stringify(cacheData));
} catch (e) {
console.warn('Cache write error:', e);
}
},
clearCache: function(url) {
if (!this.isStorageAvailable()) return;
try {
const key = this.config.cachePrefix + this.hashCode(url);
sessionStorage.removeItem(key);
} catch (e) {
console.warn('Cache clear error:', e);
}
},
/**
* 工具函数
*/
isStorageAvailable: function() {
try {
const test = '__archiver_test__';
sessionStorage.setItem(test, test);
sessionStorage.removeItem(test);
return true;
} catch (e) {
return false;
}
},
hashCode: function(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return Math.abs(hash).toString();
}
};
// 初始化
Archiver.init();
// 暴露到全局
window.WPArchiver = Archiver;
})(jQuery);

1
js/archiver.min.js vendored
View file

@ -1 +0,0 @@
(($)=>{'use strict';$(document).ready(()=>{initAdminBarTrigger();initMetaboxButton();initTabSwitching()});const initAdminBarTrigger=()=>{const $triggerButton=$('#wp-admin-bar-archiver-trigger a');if(!$triggerButton.length)return;$triggerButton.on('click',async(e)=>{e.preventDefault();const $menuItem=$(e.target).closest('li');$menuItem.addClass('archiver-active');try{const response=await wp.apiRequest({url:archiver.rest_url,method:'POST',data:{url:archiver.url},beforeSend:(xhr)=>{xhr.setRequestHeader('X-WP-Nonce',archiver.nonce)}});$menuItem.removeClass('archiver-active');if(response.success){$menuItem.addClass('archiver-success');console.log('Archiver:',response.message)}else{throw new Error(response.message||wp.i18n.__('Unknown error occurred','archiver'));}}catch(error){console.error('Archiver Error:',error);$menuItem.addClass('archiver-failure')}setTimeout(()=>{$menuItem.removeClass('archiver-success archiver-failure')},2000)})};const initMetaboxButton=()=>{const $immediateButton=$('#archiver-immediate-snapshot');$immediateButton.on('click',async(e)=>{e.preventDefault();const $statusElement=$('#archiver-status');const url=$('#archiver-url').val();const nonce=$('#archiver_nonce').val();$immediateButton.prop('disabled',true);$statusElement.show().text(archiver.i18n.triggering).removeClass('error success').addClass('processing');try{const response=await $.ajax({url:archiver.ajax_url,type:'POST',dataType:'json',data:{action:'archiver_immediate_snapshot',_ajax_nonce:nonce,url:url}});if(response.success){$statusElement.text(response.data.message).removeClass('processing').addClass('success');if(response.data.snapshots){$('#archiver-snapshots ul').html(response.data.snapshots.join(''))}}else{throw new Error(response.data.message||'Unknown error');}}catch(error){console.error('Archiver Error:',error);$statusElement.text(`${archiver.i18n.error}:${error.message||'Request failed'}`).removeClass('processing success').addClass('error')}finally{setTimeout(()=>{$immediateButton.prop('disabled',false);$statusElement.fadeOut(500,()=>{$statusElement.removeClass('processing error success').empty()})},3000)}})};const initTabSwitching=()=>{$('.nav-tab').on('click',function(e){e.preventDefault();$('.nav-tab').removeClass('nav-tab-active');$(this).addClass('nav-tab-active');$('.archiver-tab-content').hide();const tabId=$(this).data('tab');$('#'+tabId).show()})};if(!$('#archiver-spin-animation').length){$('head').append(`<style id="archiver-spin-animation">@keyframes archiver-spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style>`)}})(jQuery);

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: WP Archiver\n" "Project-Id-Version: WP Archiver\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-06 09:41+0800\n" "POT-Creation-Date: 2025-04-06 09:41+0800\n"
"PO-Revision-Date: 2025-05-27 00:18+0800\n" "PO-Revision-Date: 2025-05-28 14:29+0800\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: 简体中文\n" "Language-Team: 简体中文\n"
"Language: zh_CN\n" "Language: zh_CN\n"
@ -22,83 +22,105 @@ msgstr ""
"X-Poedit-SearchPath-0: .\n" "X-Poedit-SearchPath-0: .\n"
"X-Poedit-SearchPathExcluded-0: *.min.js\n" "X-Poedit-SearchPathExcluded-0: *.min.js\n"
#: includes/class-archiver-admin.php:969 #: includes/class-archiver-admin.php:393
msgid "%d in main queue, %d in background queue"
msgstr "%d 在主队列中,%d 在后台队列中"
#: includes/class-archiver-admin.php:1270
msgid "%d posts added to archive queue." msgid "%d posts added to archive queue."
msgstr "%d 个文章已添加到存档队列。" msgstr "%d 个文章已添加到存档队列。"
#: includes/class-archiver-admin.php:1007 #: includes/class-archiver-admin.php:1308
msgid "%d recent posts added to archive queue." msgid "%d recent posts added to archive queue."
msgstr "%d 个近期文章已添加到存档队列。" msgstr "%d 个近期文章已添加到存档队列。"
#: includes/class-archiver-admin.php:1040 #: includes/class-archiver-admin.php:1341
msgid "%d recently updated posts added to archive queue." msgid "%d recently updated posts added to archive queue."
msgstr "%d 个最近更新的文章已添加到存档队列。" msgstr "%d 个最近更新的文章已添加到存档队列。"
#: includes/class-archiver-admin.php:1172 #: includes/class-archiver-admin.php:1458
#, php-format
msgid "%s is working correctly" msgid "%s is working correctly"
msgstr "%s 工作正常" msgstr "%s 工作正常"
#: includes/class-archiver-admin.php:83 #: includes/class-archiver-dashboard.php:142
msgid "... and %d more"
msgstr "... 以及 %d 条"
#: includes/class-archiver-admin.php:118
msgid "Actions" msgid "Actions"
msgstr "操作" msgstr "操作"
#: includes/class-archiver-admin.php:1108 #: includes/class-archiver-admin.php:1418
msgid "All cache cleared successfully." msgid "All cache cleared successfully."
msgstr "所有缓存已成功清除。" msgstr "所有缓存已成功清除。"
#: includes/class-archiver-admin.php:749 #: includes/class-archiver-admin.php:972
msgid "and %d more" msgid "and %d more"
msgstr "以及 %d 个" msgstr "以及 %d 个"
#: includes/class-archiver-admin.php:686 #: includes/class-archiver-admin.php:905
msgid "API Calls Saved" msgid "API Calls Saved"
msgstr "API 调用已保存" msgstr "API 调用已保存"
#: includes/class-archiver-admin.php:199 #: includes/class-archiver-admin.php:232
msgid "Archive" msgid "Archive"
msgstr "存档" msgstr "存档"
#: includes/class-archiver-admin.php:179 #: includes/class-archiver-admin.php:212
msgid "Archive all published posts" msgid "Archive all published posts"
msgstr "存档所有已发布文章" msgstr "存档所有已发布文章"
#: includes/class-archiver-admin.php:258 #: includes/class-archiver-dashboard.php:320
msgid "Archive failed"
msgstr "存档失败"
#: includes/class-archiver-dashboard.php:491
msgid "Archive functionality not available"
msgstr "存档功能不可用"
#: includes/class-archiver-admin.php:302
msgid "Archive immediately when content is published" msgid "Archive immediately when content is published"
msgstr "内容发布后立即存档" msgstr "内容发布后立即存档"
#: includes/class-archiver.php:191 #: includes/class-archiver-dashboard.php:110
#: includes/class-archiver-dashboard.php:327 includes/class-archiver.php:301
msgid "Archive Now" msgid "Archive Now"
msgstr "立即存档" msgstr "立即存档"
#: includes/class-archiver-admin.php:248 #: includes/class-archiver-admin.php:292
msgid "Archive on Publish" msgid "Archive on Publish"
msgstr "发布时存档" msgstr "发布时存档"
#: includes/class-archiver-admin.php:180 #: includes/class-archiver-admin.php:213
msgid "Archive posts from last 30 days" msgid "Archive posts from last 30 days"
msgstr "存档过去 30 天的文章" msgstr "存档过去 30 天的文章"
#: includes/class-archiver-admin.php:181 #: includes/class-archiver-admin.php:214
msgid "Archive recently updated posts" msgid "Archive recently updated posts"
msgstr "存档最近更新的文章" msgstr "存档最近更新的文章"
#: includes/class-archiver-admin.php:68 #: includes/class-archiver-admin.php:103
msgid "Archive Services" msgid "Archive Services"
msgstr "存档服务" msgstr "存档服务"
#: includes/class-archiver-admin.php:889 #: includes/class-archiver-admin.php:1186
msgid "Archive services saved successfully." msgid "Archive services saved successfully."
msgstr "存档服务保存成功。" msgstr "存档服务保存成功。"
#: includes/class-archiver.php:149 #: includes/class-archiver.php:260
msgid "Archive Snapshots" msgid "Archive Snapshots"
msgstr "存档快照" msgstr "存档快照"
#: includes/class-archiver-admin.php:339 #: includes/class-archiver-admin.php:465
msgid "Archive Statistics" msgid "Archive Statistics"
msgstr "存档统计" msgstr "存档统计"
#: includes/class-archiver-admin.php:168 #: includes/class-archiver-dashboard.php:33
msgid "Archive Status"
msgstr "存档状态"
#: includes/class-archiver-admin.php:201
msgid "Archive Tools" msgid "Archive Tools"
msgstr "存档工具" msgstr "存档工具"
@ -107,167 +129,212 @@ msgid ""
"Archive your content using multiple archive services with advanced caching." "Archive your content using multiple archive services with advanced caching."
msgstr "使用具有高级缓存功能的多种存档服务来存档您的内容。" msgstr "使用具有高级缓存功能的多种存档服务来存档您的内容。"
#: includes/class-archiver-admin.php:39 includes/class-archiver.php:27 #: includes/class-archiver-admin.php:40 includes/class-archiver.php:27
#: includes/class-archiver.php:340 #: includes/class-archiver.php:479
msgid "Archiver" msgid "Archiver"
msgstr "时光机" msgstr "时光机"
#: includes/class-archiver-admin.php:38 #: includes/class-archiver-admin.php:39
msgid "Archiver Settings" msgid "Archiver Settings"
msgstr "时光机设置" msgstr "时光机设置"
#: includes/class-archiver.php:109 includes/class-archiver.php:130 #: includes/class-archiver.php:212 includes/class-archiver.php:241
#: includes/class-archiver.php:146 #: includes/class-archiver.php:257
msgid "Archives" msgid "Archives"
msgstr "存档" msgstr "存档"
#: includes/class-archiver-admin.php:316 #: includes/class-archiver-admin.php:444
msgid "Are you sure you want to clear all cache?" msgid "Are you sure you want to clear all cache?"
msgstr "您确定要清除所有缓存吗?" msgstr "您确定要清除所有缓存吗?"
#: includes/class-archiver-admin.php:727 #: includes/class-archiver-admin.php:946
msgid "Are you sure?" msgid "Are you sure?"
msgstr "您确定吗?" msgstr "您确定吗?"
#: includes/class-archiver-admin.php:233 #: includes/class-archiver-admin.php:277
msgid "Automatic Archiving" msgid "Automatic Archiving"
msgstr "自动存档" msgstr "自动存档"
#: includes/class-archiver-admin.php:152 #: includes/class-archiver-admin.php:184
msgid "Automation" msgid "Automation"
msgstr "自动化" msgstr "自动化"
#: includes/class-archiver-admin.php:229 #: includes/class-archiver-admin.php:271
msgid "Automation Settings" msgid "Automation Settings"
msgstr "自动化设置" msgstr "自动化设置"
#: includes/class-archiver-admin.php:174 #: includes/class-archiver-admin.php:1118
msgid "Automation settings saved successfully."
msgstr "自动化设置已成功保存。"
#: includes/class-archiver-admin.php:368
msgid "Batch Processing Size"
msgstr "批量处理大小"
#: includes/class-archiver-admin.php:207
msgid "Bulk Archive" msgid "Bulk Archive"
msgstr "批量存档" msgstr "批量存档"
#: includes/class-archiver-admin.php:170 #: includes/class-archiver-admin.php:203
msgid "Bulk archive operations and manual archiving." msgid "Bulk archive operations and manual archiving."
msgstr "批量存档操作和手动存档。" msgstr "批量存档操作和手动存档。"
#: includes/class-archiver-admin.php:310 #: includes/class-archiver-admin.php:438
msgid "Cache Actions" msgid "Cache Actions"
msgstr "缓存操作" msgstr "缓存操作"
#: includes/class-archiver-admin.php:678 #: includes/class-archiver-admin.php:897
msgid "Cache Performance" msgid "Cache Performance"
msgstr "缓存性能" msgstr "缓存性能"
#: includes/class-archiver-admin.php:1059 #: includes/class-archiver-admin.php:1362
msgid "Cache preheating started for %d posts." msgid "Cache preheating started for %d posts."
msgstr "已开始为 %d 个文章进行缓存预热。" msgstr "已开始为 %d 个文章进行缓存预热。"
#: includes/class-archiver-admin.php:155 includes/class-archiver-admin.php:289 #: includes/class-archiver-admin.php:187 includes/class-archiver-admin.php:415
msgid "Cache Settings" msgid "Cache Settings"
msgstr "缓存设置" msgstr "缓存设置"
#: includes/class-archiver-admin.php:690 #: includes/class-archiver-admin.php:1149
msgid "Cache settings saved successfully."
msgstr "缓存设置已成功保存。"
#: includes/class-archiver-admin.php:909
msgid "Cache Size" msgid "Cache Size"
msgstr "缓存大小" msgstr "缓存大小"
#: includes/class-archiver-admin.php:1134 #: includes/class-archiver-admin.php:68
msgid "" msgid ""
"Cache table is missing. Please deactivate and reactivate the plugin to fix " "Cache table is missing. Please deactivate and reactivate the plugin to fix "
"this issue." "this issue."
msgstr "缓存表缺失。请停用并重新激活该插件以修复此问题。" msgstr "缓存表缺失。请停用并重新激活该插件以修复此问题。"
#: includes/class-archiver-admin.php:682 #: includes/class-archiver-admin.php:901
msgid "Cached URLs" msgid "Cached URLs"
msgstr "缓存的 URL" msgstr "缓存的 URL"
#: includes/class-archiver-admin.php:305 #: includes/class-archiver-admin.php:433
msgid "Caching reduces API calls and improves page load times" msgid "Caching reduces API calls and improves page load times"
msgstr "缓存减少 API 调用并缩短页面加载时间" msgstr "缓存减少 API 调用并缩短页面加载时间"
#: includes/class-archiver-admin.php:95 includes/class-archiver.php:473 #: includes/class-archiver-admin.php:130 includes/class-archiver.php:612
msgid "Checking..." msgid "Checking..."
msgstr "检查..." msgstr "检查..."
#: includes/class-archiver-admin.php:317 #: includes/class-archiver-admin.php:445
msgid "Clear Cache" msgid "Clear Cache"
msgstr "清除缓存" msgstr "清除缓存"
#: includes/class-archiver-admin.php:728 #: includes/class-archiver-admin.php:947
msgid "Clear Queue" msgid "Clear Queue"
msgstr "清除队列" msgstr "清除队列"
#: includes/class-archiver-admin.php:139 #: includes/class-archiver-admin.php:174
msgid "Configure automatic archiving and content types." msgid "Configure automatic archiving and content types."
msgstr "配置自动存档和内容类型。" msgstr "配置自动存档和内容类型。"
#: includes/class-archiver-admin.php:291 #: includes/class-archiver-admin.php:417
msgid "Configure caching to improve performance." msgid "Configure caching to improve performance."
msgstr "配置缓存以提高性能。" msgstr "配置缓存以提高性能。"
#: includes/class-archiver-admin.php:70 #: includes/class-archiver-admin.php:347
msgid "Configure queue size and batch processing settings."
msgstr "配置队列大小和批处理设置。"
#: includes/class-archiver-admin.php:105
msgid "Configure which archive services to use for your content." msgid "Configure which archive services to use for your content."
msgstr "配置用于您的内容的存档服务。" msgstr "配置用于您的内容的存档服务。"
#: includes/class-archiver.php:477 #: includes/class-archiver.php:616
msgid "Connection failed" msgid "Connection failed"
msgstr "连接失败" msgstr "连接失败"
#: includes/class-archiver.php:476 #: includes/class-archiver.php:615
msgid "Connection successful" msgid "Connection successful"
msgstr "连接成功" msgstr "连接成功"
#: includes/class-archiver-admin.php:149 #: includes/class-archiver-admin.php:181
msgid "Content Types" msgid "Content Types"
msgstr "内容类型" msgstr "内容类型"
#: includes/class-archiver-admin.php:273 #: includes/class-archiver-admin.php:1090
msgid "Content types saved successfully."
msgstr "内容类型保存成功。"
#: includes/class-archiver-admin.php:383
msgid "Current Queue Status"
msgstr "当前队列状态"
#: includes/class-archiver-admin.php:323
msgid "Daily" msgid "Daily"
msgstr "每天" msgstr "每天"
#: includes/class-archiver-admin.php:62 #: includes/class-archiver-admin.php:95
msgid "Document" msgid "Document"
msgstr "文档" msgstr "文档"
#: includes/class-archiver-admin.php:243 #: includes/class-archiver-admin.php:287
msgid "Enable automatic archiving of content" msgid "Enable automatic archiving of content"
msgstr "启用内容自动存档" msgstr "启用内容自动存档"
#: includes/class-archiver-admin.php:295 #: includes/class-archiver-admin.php:423
msgid "Enable Cache" msgid "Enable Cache"
msgstr "启用缓存" msgstr "启用缓存"
#: includes/class-archiver-admin.php:1123 #: includes/class-archiver-admin.php:57
msgid "Enable caching to improve performance and reduce API calls." msgid "Enable caching to improve performance and reduce API calls."
msgstr "启用缓存以提高性能并减少 API 调用。" msgstr "启用缓存以提高性能并减少 API 调用。"
#: includes/class-archiver-admin.php:81 #: includes/class-archiver-admin.php:116
msgid "Enabled" msgid "Enabled"
msgstr "已启用" msgstr "已启用"
#: includes/class-archiver-admin.php:196 #: includes/class-archiver-admin.php:229
#: includes/class-archiver-dashboard.php:108
msgid "Enter URL to archive..." msgid "Enter URL to archive..."
msgstr "输入要存档的 URL..." msgstr "输入要存档的 URL..."
#: includes/class-archiver-admin.php:184 #: includes/class-archiver-admin.php:1420
msgid "Error clearing cache: "
msgstr "清除缓存时出错:"
#: includes/class-archiver-admin.php:311 includes/class-archiver.php:185
msgid "Every 15 Minutes"
msgstr "每15分钟"
#: includes/class-archiver-admin.php:314 includes/class-archiver.php:191
msgid "Every 30 Minutes"
msgstr "每30分钟"
#: includes/class-archiver.php:197
msgid "Exactly Every Hour"
msgstr "每小时"
#: includes/class-archiver-admin.php:217
msgid "Execute" msgid "Execute"
msgstr "执行" msgstr "执行"
#: includes/class-archiver-admin.php:638 #: includes/class-archiver-dashboard.php:91
msgid "Failed"
msgstr "失败"
#: includes/class-archiver-admin.php:826
msgid "Failed Snapshots" msgid "Failed Snapshots"
msgstr "失败快照" msgstr "失败快照"
#: includes/class-archiver.php:261 includes/class-archiver.php:470 #: includes/class-archiver.php:609
msgid "Failed to trigger snapshot." msgid "Failed to trigger snapshot."
msgstr "无法触发快照。" msgstr "无法触发快照。"
#: includes/class-archiver-admin.php:137 #: includes/class-archiver-admin.php:172
msgid "General Settings" msgid "General Settings"
msgstr "常规设置" msgstr "常规设置"
#: includes/class-archiver-admin.php:267 #: includes/class-archiver-admin.php:317
msgid "Hourly" msgid "Hourly"
msgstr "每小时" msgstr "每小时"
#: includes/class-archiver-admin.php:280 #: includes/class-archiver-admin.php:330
msgid "How often should the plugin process pending archives?" msgid "How often should the plugin process pending archives?"
msgstr "插件应该多久处理一次待处理的档案?" msgstr "插件应该多久处理一次待处理的档案?"
@ -279,275 +346,416 @@ msgstr "http://wenpai.org/plugins/wp-archiver"
msgid "https://wenpai.org/" msgid "https://wenpai.org/"
msgstr "https://wenpai.org/" msgstr "https://wenpai.org/"
#: includes/class-archiver-admin.php:1163 #: includes/class-archiver-admin.php:1449
msgid "Invalid service" msgid "Invalid service"
msgstr "无效服务" msgstr "无效服务"
#: includes/class-archiver.php:206 #: includes/class-archiver.php:316
msgid "Invalid URL" msgid "Invalid URL"
msgstr "无效的网址" msgstr "无效的网址"
#: includes/class-archiver.php:237 #: includes/class-archiver.php:355
msgid "Invalid URL." msgid "Invalid URL."
msgstr "无效的 URL。" msgstr "无效的 URL。"
#: includes/class-archiver-admin.php:642 #: includes/class-archiver-admin.php:830
msgid "Last Run" msgid "Last Run"
msgstr "上次运行" msgstr "上次运行"
#: includes/class-archiver.php:184 includes/class-archiver.php:467 #: includes/class-archiver-dashboard.php:97
msgid "Last Run:"
msgstr "上次运行:"
#: includes/class-archiver.php:295 includes/class-archiver.php:606
msgid "Loading snapshots..." msgid "Loading snapshots..."
msgstr "正在加载快照..." msgstr "正在加载快照..."
#: includes/class-archiver.php:348 #: includes/class-archiver.php:487
msgid "Loading..." msgid "Loading..."
msgstr "加载中..." msgstr "加载中..."
#: includes/class-archiver-admin.php:190 #: includes/class-archiver-admin.php:223
msgid "Manual Archive" msgid "Manual Archive"
msgstr "手册存档" msgstr "手册存档"
#: includes/class-archiver-admin.php:624 #: includes/class-archiver-admin.php:1204
msgid "Manual update function not available."
msgstr "手动更新功能不可用。"
#: includes/class-archiver-admin.php:363
msgid ""
"Maximum number of URLs that can be queued for archiving. Higher values use "
"more memory."
msgstr "可排队等待归档的 URL 数量上限。值越高,占用的内存越多。"
#: includes/class-archiver-admin.php:353
msgid "Maximum Queue Size"
msgstr "最大队列大小"
#: includes/class-archiver-admin.php:812
msgid "Metric" msgid "Metric"
msgstr "指标" msgstr "指标"
#: includes/class-archiver-admin.php:618 #: includes/class-archiver-admin.php:795
#: includes/class-archiver-dashboard.php:64
msgid "Never" msgid "Never"
msgstr "从未" msgstr "从未"
#: includes/class-archiver-admin.php:646 #: includes/class-archiver-admin.php:834
msgid "Next Run" msgid "Next Run"
msgstr "下次运行" msgstr "下次运行"
#: includes/class-archiver.php:471 #: includes/class-archiver-dashboard.php:101
msgid "Next Run:"
msgstr "下次运行:"
#: includes/class-archiver.php:610
msgid "No archives yet." msgid "No archives yet."
msgstr "尚无档案。" msgstr "尚无档案。"
#: includes/class-archiver.php:217 #: includes/class-archiver.php:335
msgid "No archives yet. A snapshot request has been scheduled." msgid "No archives yet. A snapshot request has been scheduled."
msgstr "尚无存档。已安排快照请求。" msgstr "尚无存档。已安排快照请求。"
#: includes/class-archiver-admin.php:705 #: includes/class-archiver-admin.php:924
msgid "No pending URLs in the queue." msgid "No pending URLs in the queue."
msgstr "队列中没有待处理的 URL。" msgstr "队列中没有待处理的 URL。"
#: includes/class-archiver-admin.php:649 #: includes/class-archiver-admin.php:847
#: includes/class-archiver-dashboard.php:413
msgid "Not available"
msgstr "无法使用"
#: includes/class-archiver-admin.php:804
#: includes/class-archiver-dashboard.php:75 includes/class-archiver.php:1087
msgid "Not scheduled" msgid "Not scheduled"
msgstr "无计划任务" msgstr "无计划任务"
#: includes/class-archiver.php:475 #: includes/class-archiver-admin.php:378
msgid ""
"Number of URLs to process at once during scheduled tasks. Higher values "
"process faster but use more resources."
msgstr ""
"计划任务期间一次处理的 URL 数量。值越高,处理速度越快,但消耗的资源也越多。"
#: includes/class-archiver.php:614
msgid "Offline" msgid "Offline"
msgstr "离线" msgstr "离线"
#: includes/class-archiver-admin.php:563 includes/class-archiver.php:474 #: includes/class-archiver-admin.php:695 includes/class-archiver.php:613
msgid "Online" msgid "Online"
msgstr "在线" msgstr "在线"
#: includes/class-archiver-admin.php:340 #: includes/class-archiver-admin.php:466
msgid "Overview of your archive activity and performance." msgid "Overview of your archive activity and performance."
msgstr "您的存档活动和性能的概述。" msgstr "您的存档活动和性能的概述。"
#: includes/class-archiver-admin.php:634 #: includes/class-archiver-dashboard.php:87
msgid "Pending"
msgstr "待处理"
#: includes/class-archiver-admin.php:822
msgid "Pending URLs" msgid "Pending URLs"
msgstr "待定 URL" msgstr "待定 URL"
#: includes/class-archiver-admin.php:1122 #: includes/class-archiver-admin.php:190
msgid "Performance"
msgstr "性能调整"
#: includes/class-archiver-admin.php:346
msgid "Performance Settings"
msgstr "性能设置"
#: includes/class-archiver-admin.php:1137
msgid "Performance settings saved successfully."
msgstr "性能设置保存成功。"
#: includes/class-archiver-admin.php:56
msgid "Performance Tip:" msgid "Performance Tip:"
msgstr "性能提示:" msgstr "性能提示:"
#: includes/class-archiver.php:230 #: includes/class-archiver-dashboard.php:461
#: includes/class-archiver-dashboard.php:502
msgid "Permission denied"
msgstr "无权限"
#: includes/class-archiver-admin.php:1078
#: includes/class-archiver-admin.php:1095
#: includes/class-archiver-admin.php:1123
#: includes/class-archiver-admin.php:1142
#: includes/class-archiver-admin.php:1154
#: includes/class-archiver-admin.php:1164
#: includes/class-archiver-admin.php:1191
#: includes/class-archiver-admin.php:1210
#: includes/class-archiver-admin.php:1348
#: includes/class-archiver-admin.php:1374 includes/class-archiver.php:348
msgid "Permission denied." msgid "Permission denied."
msgstr "没有权限。" msgstr "没有权限。"
#: includes/class-archiver-admin.php:876 #: includes/class-archiver-admin.php:1173
msgid "Please enable at least one archive service." msgid "Please enable at least one archive service."
msgstr "请至少启用一项存档服务。" msgstr "请至少启用一项存档服务。"
#: includes/class-archiver-admin.php:1077 #: includes/class-archiver-dashboard.php:300
#: includes/class-archiver-dashboard.php:481
msgid "Please enter a valid URL"
msgstr "请输入有效的 URL"
#: includes/class-archiver-admin.php:1381
msgid "Please enter a valid URL." msgid "Please enter a valid URL."
msgstr "请输入有效的 URL。" msgstr "请输入有效的 URL。"
#: includes/class-archiver-admin.php:935 #: includes/class-archiver-admin.php:1236
#| msgid "Please select a valid bulk action." #| msgid "Please select a valid bulk action."
msgid "Please select a valid action." msgid "Please select a valid action."
msgstr "请选择有效的批量操作。" msgstr "请选择有效的批量操作。"
#: includes/class-archiver-admin.php:836 #: includes/class-archiver-admin.php:1085
msgid "Please select at least one post type." msgid "Please select at least one post type."
msgstr "请选择至少一种文章类型。" msgstr "请选择至少一种文章类型。"
#: includes/class-archiver-admin.php:208 #: includes/class-archiver-admin.php:241
#| msgid "Content Types to Archive" #| msgid "Content Types to Archive"
msgid "Post Types to Archive" msgid "Post Types to Archive"
msgstr "要存档的内容类型" msgstr "要存档的内容类型"
#: includes/class-archiver-admin.php:313 #: includes/class-archiver-admin.php:441
msgid "Preheat Cache" msgid "Preheat Cache"
msgstr "预热缓存" msgstr "预热缓存"
#: includes/class-archiver-admin.php:320 #: includes/class-archiver-admin.php:448
msgid "Preheat cache for recent posts or clear all cached data." msgid "Preheat cache for recent posts or clear all cached data."
msgstr "预热最近文章的缓存或清除所有缓存数据。" msgstr "预热最近文章的缓存或清除所有缓存数据。"
#: includes/class-archiver-admin.php:82 #: includes/class-archiver-admin.php:117
msgid "Primary" msgid "Primary"
msgstr "主要" msgstr "主要"
#: includes/class-archiver-admin.php:882 #: includes/class-archiver-admin.php:1179
msgid "Primary service must be enabled." msgid "Primary service must be enabled."
msgstr "必须启用主要服务。" msgstr "必须启用主要服务。"
#: includes/class-archiver-admin.php:719 #: includes/class-archiver-dashboard.php:351
msgid "Process failed"
msgstr "进程失败"
#: includes/class-archiver-dashboard.php:115
#: includes/class-archiver-dashboard.php:358
msgid "Process Queue"
msgstr "进程队列"
#: includes/class-archiver-admin.php:938
msgid "Process Queue Now" msgid "Process Queue Now"
msgstr "立即处理队列" msgstr "立即处理队列"
#: includes/class-archiver-admin.php:902 #: includes/class-archiver-admin.php:1200
msgid "Processing started for %d URLs." msgid "Processing started for %d URLs."
msgstr "已开始处理 %d 个 URL。" msgstr "已开始处理 %d 个 URL。"
#: includes/class-archiver-admin.php:931 #: includes/class-archiver-dashboard.php:304
#: includes/class-archiver-dashboard.php:336
msgid "Processing..."
msgstr "队列处理中..."
#: includes/class-archiver-admin.php:1232
msgid "Queue cleared successfully." msgid "Queue cleared successfully."
msgstr "队列清除成功。" msgstr "队列清除成功。"
#: includes/class-archiver-admin.php:146 includes/class-archiver-admin.php:163 #: includes/class-archiver-admin.php:398
msgid ""
"Queue is nearly full. Consider increasing the maximum queue size or "
"processing more URLs per batch."
msgstr "队列几乎已满。请考虑增加最大队列大小或每批次处理更多 URL。"
#: includes/class-archiver-admin.php:178 includes/class-archiver-admin.php:196
msgid "Queue Management" msgid "Queue Management"
msgstr "队列管理" msgstr "队列管理"
#: includes/class-archiver-admin.php:129 #: includes/class-archiver-dashboard.php:472
msgid "Queue processing not available"
msgstr "队列处理不可用"
#: includes/class-archiver-dashboard.php:127
msgid "Recent Queue Items"
msgstr "最近的队列项目"
#: includes/class-archiver-dashboard.php:118
msgid "Refresh Stats"
msgstr "刷新统计数据"
#: includes/class-archiver-dashboard.php:324
#: includes/class-archiver-dashboard.php:355
msgid "Request failed"
msgstr "请求失败"
#: includes/class-archiver-admin.php:338
msgid "Save Automation Settings"
msgstr "保存自动化设置"
#: includes/class-archiver-admin.php:456
msgid "Save Cache Settings"
msgstr "保存缓存设置"
#: includes/class-archiver-admin.php:263
msgid "Save Content Types"
msgstr "保存内容类型"
#: includes/class-archiver-admin.php:407
msgid "Save Performance Settings"
msgstr "保存性能设置"
#: includes/class-archiver-admin.php:164
msgid "Save Services" msgid "Save Services"
msgstr "保存服务" msgstr "保存服务"
#: includes/class-archiver-admin.php:331 #: includes/class-archiver-admin.php:996 includes/class-archiver-admin.php:1005
msgid "Save Settings" #: includes/class-archiver-admin.php:1014
msgstr "保存设置" #: includes/class-archiver-admin.php:1023
#: includes/class-archiver-admin.php:1032
#: includes/class-archiver-admin.php:776 includes/class-archiver-admin.php:785 #: includes/class-archiver-admin.php:1041
#: includes/class-archiver-admin.php:794 includes/class-archiver-admin.php:803 #: includes/class-archiver-admin.php:1050
#: includes/class-archiver-admin.php:812 includes/class-archiver-admin.php:821 #: includes/class-archiver-admin.php:1060
#: includes/class-archiver.php:226 #: includes/class-archiver-admin.php:1069 includes/class-archiver.php:344
msgid "Security check failed." msgid "Security check failed."
msgstr "安全检查失败。" msgstr "安全检查失败。"
#: includes/class-archiver.php:319 includes/class-archiver.php:472 #: includes/class-archiver-admin.php:211
#| msgid "See all snapshots ↗"
msgid "See all snapshots"
msgstr "查看所有快照 ↗"
#: includes/class-archiver-admin.php:178
#| msgid "Select bulk action..." #| msgid "Select bulk action..."
msgid "Select action..." msgid "Select action..."
msgstr "选择批量操作..." msgstr "选择批量操作..."
#: includes/class-archiver-admin.php:209 #: includes/class-archiver-admin.php:242
msgid "Select which content types should be automatically archived." msgid "Select which content types should be automatically archived."
msgstr "选择应自动存档的内容类型。" msgstr "选择应自动存档的内容类型。"
#: includes/class-archiver-admin.php:79 #: includes/class-archiver-admin.php:114
msgid "Service" msgid "Service"
msgstr "服务" msgstr "服务"
#: includes/class-archiver-admin.php:1150 #: includes/class-archiver-admin.php:1435
msgid "Service is operational" msgid "Service is operational"
msgstr "服务已运行" msgstr "服务已运行"
#: wp-archiver.php:243 #: wp-archiver.php:245
msgid "Settings" msgid "Settings"
msgstr "设置" msgstr "设置"
#: includes/class-archiver-admin.php:863 #: includes/class-archiver-admin.php:1159
msgid "Settings saved successfully." msgid "Settings saved successfully."
msgstr "设置保存成功。" msgstr "设置保存成功。"
#: includes/class-archiver-admin.php:742 #: includes/class-archiver-admin.php:963
msgid "Show queue details" msgid "Show queue details"
msgstr "显示队列详细信息" msgstr "显示队列详细信息"
#: includes/class-archiver.php:562 #: includes/class-archiver.php:709
msgid "Snapshot request recorded." msgid "Snapshot request recorded."
msgstr "快照请求已记录。" msgstr "快照请求已记录。"
#: includes/class-archiver.php:257 #: includes/class-archiver.php:384
msgid "Snapshot request submitted to %d service(s)." msgid "Snapshot request submitted and will be processed shortly."
msgstr "快照请求已提交给 %d 个服务。" msgstr "快照请求已提交,将很快处理。"
#: includes/class-archiver.php:469 #: includes/class-archiver.php:608
msgid "Snapshot triggered successfully!" msgid "Snapshot triggered successfully!"
msgstr "快照触发成功!" msgstr "快照触发成功!"
#: includes/class-archiver-admin.php:80 #: includes/class-archiver-dashboard.php:469
msgid "Started processing %d URLs from queue"
msgstr "已开始处理队列中的 %d 个 URL"
#: includes/class-archiver-admin.php:115
msgid "Status" msgid "Status"
msgstr "状态" msgstr "状态"
#: includes/class-archiver-admin.php:63 #: includes/class-archiver-admin.php:96
msgid "Support" msgid "Support"
msgstr "支持" msgstr "支持"
#: includes/class-archiver-admin.php:118 #: includes/class-archiver-admin.php:153
msgid "Test Connect" #| msgid "Test Connect"
msgid "Test Connection"
msgstr "测试连接" msgstr "测试连接"
#: includes/class-archiver-admin.php:599 #: includes/class-archiver-admin.php:731
msgid "Test failed" msgid "Test failed"
msgstr "测试失败" msgstr "测试失败"
#: includes/class-archiver-admin.php:576 #: includes/class-archiver-admin.php:708
msgid "Testing..." msgid "Testing..."
msgstr "正在测试..." msgstr "正在测试..."
#: includes/class-archiver.php:218 #: includes/class-archiver.php:336
msgid "There are no archives of this URL." msgid "There are no archives of this URL."
msgstr "此 URL 没有存档。" msgstr "此 URL 没有存档。"
#: includes/class-archiver-admin.php:630 #: includes/class-archiver-admin.php:818
#: includes/class-archiver-dashboard.php:83
msgid "Total Archived" msgid "Total Archived"
msgstr "总存档" msgstr "总存档"
#: includes/class-archiver-admin.php:712 #: includes/class-archiver-admin.php:931
msgid "Total Pending:" msgid "Total Pending:"
msgstr "待处理总数:" msgstr "待处理总数:"
#: includes/class-archiver.php:356 #: includes/class-archiver.php:495
msgid "Trigger Snapshot" msgid "Trigger Snapshot"
msgstr "触发快照" msgstr "触发快照"
#: includes/class-archiver.php:468 #: includes/class-archiver.php:607
msgid "Triggering snapshot..." msgid "Triggering snapshot..."
msgstr "正在触发快照..." msgstr "正在触发快照..."
#: includes/class-archiver-admin.php:270 #: includes/class-archiver-admin.php:320
msgid "Twice Daily" msgid "Twice Daily"
msgstr "每天两次" msgstr "每天两次"
#: includes/class-archiver-admin.php:263 #: includes/class-archiver-admin.php:307
msgid "Update Frequency" msgid "Update Frequency"
msgstr "更新频率" msgstr "更新频率"
#: includes/class-archiver-admin.php:1089 #: includes/class-archiver-admin.php:1398
#: includes/class-archiver-dashboard.php:488
#, php-format
msgid "URL added to archive queue: %s" msgid "URL added to archive queue: %s"
msgstr "已将 URL 添加到存档队列:%s" msgstr "已将 URL 添加到存档队列:%s"
#: includes/class-archiver-admin.php:713 #: includes/class-archiver-admin.php:932
msgid "URLs" msgid "URLs"
msgstr "网址" msgstr "网址"
#: includes/class-archiver-admin.php:625 #: includes/class-archiver-admin.php:390
msgid "URLs pending"
msgstr "网址待定"
#: includes/class-archiver-admin.php:813
msgid "Value" msgid "Value"
msgstr "数值" msgstr "数值"
#: includes/class-archiver-admin.php:61 #: includes/class-archiver-admin.php:94
#, php-format #, php-format
msgid "Version: %s" msgid "Version: %s"
msgstr "版本:%s" msgstr "版本:%s"
#: includes/class-archiver-admin.php:164 #: includes/class-archiver.php:458 includes/class-archiver.php:611
#| msgid "See all snapshots"
msgid "View all snapshots"
msgstr "查看所有快照 ↗"
#: includes/class-archiver-admin.php:197
msgid "View and manage the archive queue." msgid "View and manage the archive queue."
msgstr "查看和管理存档队列。" msgstr "查看和管理存档队列。"
#: includes/class-archiver.php:369 #: includes/class-archiver.php:508
#, php-format
msgid "View on %s" msgid "View on %s"
msgstr "查看 %s" msgstr "查看 %s"
#: includes/class-archiver-admin.php:276 #: includes/class-archiver-admin.php:397
msgid "Warning:"
msgstr "警告:"
#: includes/class-archiver-admin.php:326
msgid "Weekly" msgid "Weekly"
msgstr "每周" msgstr "每周"
@ -559,14 +767,14 @@ msgstr "文派开源"
msgid "WP Archiver" msgid "WP Archiver"
msgstr "文派时光机" msgstr "文派时光机"
#: wp-archiver.php:254 #: wp-archiver.php:256
msgid "WP Archiver requires PHP 5.6 or higher." msgid "WP Archiver requires PHP 5.6 or higher."
msgstr "WP Archiver 需要 PHP 5.6 或更高版本。" msgstr "WP Archiver 需要 PHP 5.6 或更高版本。"
#: wp-archiver.php:262 #: wp-archiver.php:264
msgid "WP Archiver requires WordPress 4.9 or higher." msgid "WP Archiver requires WordPress 4.9 or higher."
msgstr "WP Archiver 需要 WordPress 4.9 或更高版本。" msgstr "WP Archiver 需要 WordPress 4.9 或更高版本。"
#: includes/class-archiver-admin.php:48 #: includes/class-archiver-admin.php:75
msgid "You do not have sufficient permissions to access this page." msgid "You do not have sufficient permissions to access this page."
msgstr "您没有足够的权限访问此页面。" msgstr "您没有足够的权限访问此页面。"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WP Archiver\n" "Project-Id-Version: WP Archiver\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-05-26 16:07+0000\n" "POT-Creation-Date: 2025-05-28 06:23+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: \n" "Language-Team: \n"
@ -16,84 +16,105 @@ msgstr ""
"X-Loco-Version: 2.6.11; wp-6.7.2\n" "X-Loco-Version: 2.6.11; wp-6.7.2\n"
"X-Domain: archiver" "X-Domain: archiver"
#: includes/class-archiver-admin.php:969 #: includes/class-archiver-admin.php:393
msgid "%d in main queue, %d in background queue"
msgstr ""
#: includes/class-archiver-admin.php:1270
msgid "%d posts added to archive queue." msgid "%d posts added to archive queue."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1007 #: includes/class-archiver-admin.php:1308
msgid "%d recent posts added to archive queue." msgid "%d recent posts added to archive queue."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1040 #: includes/class-archiver-admin.php:1341
msgid "%d recently updated posts added to archive queue." msgid "%d recently updated posts added to archive queue."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1172 #: includes/class-archiver-admin.php:1458
#, php-format #, php-format
msgid "%s is working correctly" msgid "%s is working correctly"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:83 #: includes/class-archiver-dashboard.php:142
msgid "... and %d more"
msgstr ""
#: includes/class-archiver-admin.php:118
msgid "Actions" msgid "Actions"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1108 #: includes/class-archiver-admin.php:1418
msgid "All cache cleared successfully." msgid "All cache cleared successfully."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:749 #: includes/class-archiver-admin.php:972
msgid "and %d more" msgid "and %d more"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:686 #: includes/class-archiver-admin.php:905
msgid "API Calls Saved" msgid "API Calls Saved"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:199 #: includes/class-archiver-admin.php:232
msgid "Archive" msgid "Archive"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:179 #: includes/class-archiver-admin.php:212
msgid "Archive all published posts" msgid "Archive all published posts"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:258 #: includes/class-archiver-dashboard.php:320
msgid "Archive failed"
msgstr ""
#: includes/class-archiver-dashboard.php:491
msgid "Archive functionality not available"
msgstr ""
#: includes/class-archiver-admin.php:302
msgid "Archive immediately when content is published" msgid "Archive immediately when content is published"
msgstr "" msgstr ""
#: includes/class-archiver.php:191 #: includes/class-archiver-dashboard.php:110
#: includes/class-archiver-dashboard.php:327 includes/class-archiver.php:301
msgid "Archive Now" msgid "Archive Now"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:248 #: includes/class-archiver-admin.php:292
msgid "Archive on Publish" msgid "Archive on Publish"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:180 #: includes/class-archiver-admin.php:213
msgid "Archive posts from last 30 days" msgid "Archive posts from last 30 days"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:181 #: includes/class-archiver-admin.php:214
msgid "Archive recently updated posts" msgid "Archive recently updated posts"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:68 #: includes/class-archiver-admin.php:103
msgid "Archive Services" msgid "Archive Services"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:889 #: includes/class-archiver-admin.php:1186
msgid "Archive services saved successfully." msgid "Archive services saved successfully."
msgstr "" msgstr ""
#: includes/class-archiver.php:149 #: includes/class-archiver.php:260
msgid "Archive Snapshots" msgid "Archive Snapshots"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:339 #: includes/class-archiver-admin.php:465
msgid "Archive Statistics" msgid "Archive Statistics"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:168 #: includes/class-archiver-dashboard.php:33
msgid "Archive Status"
msgstr ""
#: includes/class-archiver-admin.php:201
msgid "Archive Tools" msgid "Archive Tools"
msgstr "" msgstr ""
@ -102,167 +123,212 @@ msgid ""
"Archive your content using multiple archive services with advanced caching." "Archive your content using multiple archive services with advanced caching."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:39 includes/class-archiver.php:27 #: includes/class-archiver-admin.php:40 includes/class-archiver.php:27
#: includes/class-archiver.php:340 #: includes/class-archiver.php:479
msgid "Archiver" msgid "Archiver"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:38 #: includes/class-archiver-admin.php:39
msgid "Archiver Settings" msgid "Archiver Settings"
msgstr "" msgstr ""
#: includes/class-archiver.php:109 includes/class-archiver.php:130 #: includes/class-archiver.php:212 includes/class-archiver.php:241
#: includes/class-archiver.php:146 #: includes/class-archiver.php:257
msgid "Archives" msgid "Archives"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:316 #: includes/class-archiver-admin.php:444
msgid "Are you sure you want to clear all cache?" msgid "Are you sure you want to clear all cache?"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:727 #: includes/class-archiver-admin.php:946
msgid "Are you sure?" msgid "Are you sure?"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:233 #: includes/class-archiver-admin.php:277
msgid "Automatic Archiving" msgid "Automatic Archiving"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:152 #: includes/class-archiver-admin.php:184
msgid "Automation" msgid "Automation"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:229 #: includes/class-archiver-admin.php:271
msgid "Automation Settings" msgid "Automation Settings"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:174 #: includes/class-archiver-admin.php:1118
msgid "Automation settings saved successfully."
msgstr ""
#: includes/class-archiver-admin.php:368
msgid "Batch Processing Size"
msgstr ""
#: includes/class-archiver-admin.php:207
msgid "Bulk Archive" msgid "Bulk Archive"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:170 #: includes/class-archiver-admin.php:203
msgid "Bulk archive operations and manual archiving." msgid "Bulk archive operations and manual archiving."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:310 #: includes/class-archiver-admin.php:438
msgid "Cache Actions" msgid "Cache Actions"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:678 #: includes/class-archiver-admin.php:897
msgid "Cache Performance" msgid "Cache Performance"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1059 #: includes/class-archiver-admin.php:1362
msgid "Cache preheating started for %d posts." msgid "Cache preheating started for %d posts."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:155 includes/class-archiver-admin.php:289 #: includes/class-archiver-admin.php:187 includes/class-archiver-admin.php:415
msgid "Cache Settings" msgid "Cache Settings"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:690 #: includes/class-archiver-admin.php:1149
msgid "Cache settings saved successfully."
msgstr ""
#: includes/class-archiver-admin.php:909
msgid "Cache Size" msgid "Cache Size"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1134 #: includes/class-archiver-admin.php:68
msgid "" msgid ""
"Cache table is missing. Please deactivate and reactivate the plugin to fix " "Cache table is missing. Please deactivate and reactivate the plugin to fix "
"this issue." "this issue."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:682 #: includes/class-archiver-admin.php:901
msgid "Cached URLs" msgid "Cached URLs"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:305 #: includes/class-archiver-admin.php:433
msgid "Caching reduces API calls and improves page load times" msgid "Caching reduces API calls and improves page load times"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:95 includes/class-archiver.php:473 #: includes/class-archiver-admin.php:130 includes/class-archiver.php:612
msgid "Checking..." msgid "Checking..."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:317 #: includes/class-archiver-admin.php:445
msgid "Clear Cache" msgid "Clear Cache"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:728 #: includes/class-archiver-admin.php:947
msgid "Clear Queue" msgid "Clear Queue"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:139 #: includes/class-archiver-admin.php:174
msgid "Configure automatic archiving and content types." msgid "Configure automatic archiving and content types."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:291 #: includes/class-archiver-admin.php:417
msgid "Configure caching to improve performance." msgid "Configure caching to improve performance."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:70 #: includes/class-archiver-admin.php:347
msgid "Configure queue size and batch processing settings."
msgstr ""
#: includes/class-archiver-admin.php:105
msgid "Configure which archive services to use for your content." msgid "Configure which archive services to use for your content."
msgstr "" msgstr ""
#: includes/class-archiver.php:477 #: includes/class-archiver.php:616
msgid "Connection failed" msgid "Connection failed"
msgstr "" msgstr ""
#: includes/class-archiver.php:476 #: includes/class-archiver.php:615
msgid "Connection successful" msgid "Connection successful"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:149 #: includes/class-archiver-admin.php:181
msgid "Content Types" msgid "Content Types"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:273 #: includes/class-archiver-admin.php:1090
msgid "Content types saved successfully."
msgstr ""
#: includes/class-archiver-admin.php:383
msgid "Current Queue Status"
msgstr ""
#: includes/class-archiver-admin.php:323
msgid "Daily" msgid "Daily"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:62 #: includes/class-archiver-admin.php:95
msgid "Document" msgid "Document"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:243 #: includes/class-archiver-admin.php:287
msgid "Enable automatic archiving of content" msgid "Enable automatic archiving of content"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:295 #: includes/class-archiver-admin.php:423
msgid "Enable Cache" msgid "Enable Cache"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1123 #: includes/class-archiver-admin.php:57
msgid "Enable caching to improve performance and reduce API calls." msgid "Enable caching to improve performance and reduce API calls."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:81 #: includes/class-archiver-admin.php:116
msgid "Enabled" msgid "Enabled"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:196 #: includes/class-archiver-admin.php:229
#: includes/class-archiver-dashboard.php:108
msgid "Enter URL to archive..." msgid "Enter URL to archive..."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:184 #: includes/class-archiver-admin.php:1420
msgid "Error clearing cache: "
msgstr ""
#: includes/class-archiver-admin.php:311 includes/class-archiver.php:185
msgid "Every 15 Minutes"
msgstr ""
#: includes/class-archiver-admin.php:314 includes/class-archiver.php:191
msgid "Every 30 Minutes"
msgstr ""
#: includes/class-archiver.php:197
msgid "Exactly Every Hour"
msgstr ""
#: includes/class-archiver-admin.php:217
msgid "Execute" msgid "Execute"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:638 #: includes/class-archiver-dashboard.php:91
msgid "Failed"
msgstr ""
#: includes/class-archiver-admin.php:826
msgid "Failed Snapshots" msgid "Failed Snapshots"
msgstr "" msgstr ""
#: includes/class-archiver.php:261 includes/class-archiver.php:470 #: includes/class-archiver.php:609
msgid "Failed to trigger snapshot." msgid "Failed to trigger snapshot."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:137 #: includes/class-archiver-admin.php:172
msgid "General Settings" msgid "General Settings"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:267 #: includes/class-archiver-admin.php:317
msgid "Hourly" msgid "Hourly"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:280 #: includes/class-archiver-admin.php:330
msgid "How often should the plugin process pending archives?" msgid "How often should the plugin process pending archives?"
msgstr "" msgstr ""
@ -274,273 +340,410 @@ msgstr ""
msgid "https://wenpai.org/" msgid "https://wenpai.org/"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1163 #: includes/class-archiver-admin.php:1449
msgid "Invalid service" msgid "Invalid service"
msgstr "" msgstr ""
#: includes/class-archiver.php:206 #: includes/class-archiver.php:316
msgid "Invalid URL" msgid "Invalid URL"
msgstr "" msgstr ""
#: includes/class-archiver.php:237 #: includes/class-archiver.php:355
msgid "Invalid URL." msgid "Invalid URL."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:642 #: includes/class-archiver-admin.php:830
msgid "Last Run" msgid "Last Run"
msgstr "" msgstr ""
#: includes/class-archiver.php:184 includes/class-archiver.php:467 #: includes/class-archiver-dashboard.php:97
msgid "Last Run:"
msgstr ""
#: includes/class-archiver.php:295 includes/class-archiver.php:606
msgid "Loading snapshots..." msgid "Loading snapshots..."
msgstr "" msgstr ""
#: includes/class-archiver.php:348 #: includes/class-archiver.php:487
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:190 #: includes/class-archiver-admin.php:223
msgid "Manual Archive" msgid "Manual Archive"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:624 #: includes/class-archiver-admin.php:1204
msgid "Manual update function not available."
msgstr ""
#: includes/class-archiver-admin.php:363
msgid ""
"Maximum number of URLs that can be queued for archiving. Higher values use "
"more memory."
msgstr ""
#: includes/class-archiver-admin.php:353
msgid "Maximum Queue Size"
msgstr ""
#: includes/class-archiver-admin.php:812
msgid "Metric" msgid "Metric"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:618 #: includes/class-archiver-admin.php:795
#: includes/class-archiver-dashboard.php:64
msgid "Never" msgid "Never"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:646 #: includes/class-archiver-admin.php:834
msgid "Next Run" msgid "Next Run"
msgstr "" msgstr ""
#: includes/class-archiver.php:471 #: includes/class-archiver-dashboard.php:101
msgid "Next Run:"
msgstr ""
#: includes/class-archiver.php:610
msgid "No archives yet." msgid "No archives yet."
msgstr "" msgstr ""
#: includes/class-archiver.php:217 #: includes/class-archiver.php:335
msgid "No archives yet. A snapshot request has been scheduled." msgid "No archives yet. A snapshot request has been scheduled."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:705 #: includes/class-archiver-admin.php:924
msgid "No pending URLs in the queue." msgid "No pending URLs in the queue."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:649 #: includes/class-archiver-admin.php:847
#: includes/class-archiver-dashboard.php:413
msgid "Not available"
msgstr ""
#: includes/class-archiver-admin.php:804
#: includes/class-archiver-dashboard.php:75 includes/class-archiver.php:1087
msgid "Not scheduled" msgid "Not scheduled"
msgstr "" msgstr ""
#: includes/class-archiver.php:475 #: includes/class-archiver-admin.php:378
msgid ""
"Number of URLs to process at once during scheduled tasks. Higher values "
"process faster but use more resources."
msgstr ""
#: includes/class-archiver.php:614
msgid "Offline" msgid "Offline"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:563 includes/class-archiver.php:474 #: includes/class-archiver-admin.php:695 includes/class-archiver.php:613
msgid "Online" msgid "Online"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:340 #: includes/class-archiver-admin.php:466
msgid "Overview of your archive activity and performance." msgid "Overview of your archive activity and performance."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:634 #: includes/class-archiver-dashboard.php:87
msgid "Pending"
msgstr ""
#: includes/class-archiver-admin.php:822
msgid "Pending URLs" msgid "Pending URLs"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1122 #: includes/class-archiver-admin.php:190
msgid "Performance"
msgstr ""
#: includes/class-archiver-admin.php:346
msgid "Performance Settings"
msgstr ""
#: includes/class-archiver-admin.php:1137
msgid "Performance settings saved successfully."
msgstr ""
#: includes/class-archiver-admin.php:56
msgid "Performance Tip:" msgid "Performance Tip:"
msgstr "" msgstr ""
#: includes/class-archiver.php:230 #: includes/class-archiver-dashboard.php:461
#: includes/class-archiver-dashboard.php:502
msgid "Permission denied"
msgstr ""
#: includes/class-archiver-admin.php:1078
#: includes/class-archiver-admin.php:1095
#: includes/class-archiver-admin.php:1123
#: includes/class-archiver-admin.php:1142
#: includes/class-archiver-admin.php:1154
#: includes/class-archiver-admin.php:1164
#: includes/class-archiver-admin.php:1191
#: includes/class-archiver-admin.php:1210
#: includes/class-archiver-admin.php:1348
#: includes/class-archiver-admin.php:1374 includes/class-archiver.php:348
msgid "Permission denied." msgid "Permission denied."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:876 #: includes/class-archiver-admin.php:1173
msgid "Please enable at least one archive service." msgid "Please enable at least one archive service."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1077 #: includes/class-archiver-dashboard.php:300
#: includes/class-archiver-dashboard.php:481
msgid "Please enter a valid URL"
msgstr ""
#: includes/class-archiver-admin.php:1381
msgid "Please enter a valid URL." msgid "Please enter a valid URL."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:935 #: includes/class-archiver-admin.php:1236
msgid "Please select a valid action." msgid "Please select a valid action."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:836 #: includes/class-archiver-admin.php:1085
msgid "Please select at least one post type." msgid "Please select at least one post type."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:208 #: includes/class-archiver-admin.php:241
msgid "Post Types to Archive" msgid "Post Types to Archive"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:313 #: includes/class-archiver-admin.php:441
msgid "Preheat Cache" msgid "Preheat Cache"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:320 #: includes/class-archiver-admin.php:448
msgid "Preheat cache for recent posts or clear all cached data." msgid "Preheat cache for recent posts or clear all cached data."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:82 #: includes/class-archiver-admin.php:117
msgid "Primary" msgid "Primary"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:882 #: includes/class-archiver-admin.php:1179
msgid "Primary service must be enabled." msgid "Primary service must be enabled."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:719 #: includes/class-archiver-dashboard.php:351
msgid "Process failed"
msgstr ""
#: includes/class-archiver-dashboard.php:115
#: includes/class-archiver-dashboard.php:358
msgid "Process Queue"
msgstr ""
#: includes/class-archiver-admin.php:938
msgid "Process Queue Now" msgid "Process Queue Now"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:902 #: includes/class-archiver-admin.php:1200
msgid "Processing started for %d URLs." msgid "Processing started for %d URLs."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:931 #: includes/class-archiver-dashboard.php:304
#: includes/class-archiver-dashboard.php:336
msgid "Processing..."
msgstr ""
#: includes/class-archiver-admin.php:1232
msgid "Queue cleared successfully." msgid "Queue cleared successfully."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:146 includes/class-archiver-admin.php:163 #: includes/class-archiver-admin.php:398
msgid ""
"Queue is nearly full. Consider increasing the maximum queue size or "
"processing more URLs per batch."
msgstr ""
#: includes/class-archiver-admin.php:178 includes/class-archiver-admin.php:196
msgid "Queue Management" msgid "Queue Management"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:129 #: includes/class-archiver-dashboard.php:472
msgid "Save Services" msgid "Queue processing not available"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:331 #: includes/class-archiver-dashboard.php:127
msgid "Save Settings" msgid "Recent Queue Items"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:776 includes/class-archiver-admin.php:785 #: includes/class-archiver-dashboard.php:118
#: includes/class-archiver-admin.php:794 includes/class-archiver-admin.php:803 msgid "Refresh Stats"
#: includes/class-archiver-admin.php:812 includes/class-archiver-admin.php:821
#: includes/class-archiver.php:226
msgid "Security check failed."
msgstr "" msgstr ""
#: includes/class-archiver.php:319 includes/class-archiver.php:472 #: includes/class-archiver-dashboard.php:324
msgid "See all snapshots" #: includes/class-archiver-dashboard.php:355
msgid "Request failed"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:178 #: includes/class-archiver-admin.php:338
msgid "Select action..." msgid "Save Automation Settings"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:209 #: includes/class-archiver-admin.php:456
msgid "Select which content types should be automatically archived." msgid "Save Cache Settings"
msgstr ""
#: includes/class-archiver-admin.php:79
msgid "Service"
msgstr ""
#: includes/class-archiver-admin.php:1150
msgid "Service is operational"
msgstr ""
#: wp-archiver.php:243
msgid "Settings"
msgstr ""
#: includes/class-archiver-admin.php:863
msgid "Settings saved successfully."
msgstr ""
#: includes/class-archiver-admin.php:742
msgid "Show queue details"
msgstr ""
#: includes/class-archiver.php:562
msgid "Snapshot request recorded."
msgstr ""
#: includes/class-archiver.php:257
msgid "Snapshot request submitted to %d service(s)."
msgstr ""
#: includes/class-archiver.php:469
msgid "Snapshot triggered successfully!"
msgstr ""
#: includes/class-archiver-admin.php:80
msgid "Status"
msgstr ""
#: includes/class-archiver-admin.php:63
msgid "Support"
msgstr ""
#: includes/class-archiver-admin.php:118
msgid "Test Connect"
msgstr ""
#: includes/class-archiver-admin.php:599
msgid "Test failed"
msgstr ""
#: includes/class-archiver-admin.php:576
msgid "Testing..."
msgstr ""
#: includes/class-archiver.php:218
msgid "There are no archives of this URL."
msgstr ""
#: includes/class-archiver-admin.php:630
msgid "Total Archived"
msgstr ""
#: includes/class-archiver-admin.php:712
msgid "Total Pending:"
msgstr ""
#: includes/class-archiver.php:356
msgid "Trigger Snapshot"
msgstr ""
#: includes/class-archiver.php:468
msgid "Triggering snapshot..."
msgstr ""
#: includes/class-archiver-admin.php:270
msgid "Twice Daily"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:263 #: includes/class-archiver-admin.php:263
msgid "Save Content Types"
msgstr ""
#: includes/class-archiver-admin.php:407
msgid "Save Performance Settings"
msgstr ""
#: includes/class-archiver-admin.php:164
msgid "Save Services"
msgstr ""
#: includes/class-archiver-admin.php:996 includes/class-archiver-admin.php:1005
#: includes/class-archiver-admin.php:1014
#: includes/class-archiver-admin.php:1023
#: includes/class-archiver-admin.php:1032
#: includes/class-archiver-admin.php:1041
#: includes/class-archiver-admin.php:1050
#: includes/class-archiver-admin.php:1060
#: includes/class-archiver-admin.php:1069 includes/class-archiver.php:344
msgid "Security check failed."
msgstr ""
#: includes/class-archiver-admin.php:211
msgid "Select action..."
msgstr ""
#: includes/class-archiver-admin.php:242
msgid "Select which content types should be automatically archived."
msgstr ""
#: includes/class-archiver-admin.php:114
msgid "Service"
msgstr ""
#: includes/class-archiver-admin.php:1435
msgid "Service is operational"
msgstr ""
#: wp-archiver.php:245
msgid "Settings"
msgstr ""
#: includes/class-archiver-admin.php:1159
msgid "Settings saved successfully."
msgstr ""
#: includes/class-archiver-admin.php:963
msgid "Show queue details"
msgstr ""
#: includes/class-archiver.php:709
msgid "Snapshot request recorded."
msgstr ""
#: includes/class-archiver.php:384
msgid "Snapshot request submitted and will be processed shortly."
msgstr ""
#: includes/class-archiver.php:608
msgid "Snapshot triggered successfully!"
msgstr ""
#: includes/class-archiver-dashboard.php:469
msgid "Started processing %d URLs from queue"
msgstr ""
#: includes/class-archiver-admin.php:115
msgid "Status"
msgstr ""
#: includes/class-archiver-admin.php:96
msgid "Support"
msgstr ""
#: includes/class-archiver-admin.php:153
msgid "Test Connection"
msgstr ""
#: includes/class-archiver-admin.php:731
msgid "Test failed"
msgstr ""
#: includes/class-archiver-admin.php:708
msgid "Testing..."
msgstr ""
#: includes/class-archiver.php:336
msgid "There are no archives of this URL."
msgstr ""
#: includes/class-archiver-admin.php:818
#: includes/class-archiver-dashboard.php:83
msgid "Total Archived"
msgstr ""
#: includes/class-archiver-admin.php:931
msgid "Total Pending:"
msgstr ""
#: includes/class-archiver.php:495
msgid "Trigger Snapshot"
msgstr ""
#: includes/class-archiver.php:607
msgid "Triggering snapshot..."
msgstr ""
#: includes/class-archiver-admin.php:320
msgid "Twice Daily"
msgstr ""
#: includes/class-archiver-admin.php:307
msgid "Update Frequency" msgid "Update Frequency"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:1089 #: includes/class-archiver-admin.php:1398
#: includes/class-archiver-dashboard.php:488
#, php-format #, php-format
msgid "URL added to archive queue: %s" msgid "URL added to archive queue: %s"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:713 #: includes/class-archiver-admin.php:932
msgid "URLs" msgid "URLs"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:625 #: includes/class-archiver-admin.php:390
msgid "URLs pending"
msgstr ""
#: includes/class-archiver-admin.php:813
msgid "Value" msgid "Value"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:61 #: includes/class-archiver-admin.php:94
#, php-format #, php-format
msgid "Version: %s" msgid "Version: %s"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:164 #: includes/class-archiver.php:458 includes/class-archiver.php:611
msgid "View all snapshots"
msgstr ""
#: includes/class-archiver-admin.php:197
msgid "View and manage the archive queue." msgid "View and manage the archive queue."
msgstr "" msgstr ""
#: includes/class-archiver.php:369 #: includes/class-archiver.php:508
#, php-format #, php-format
msgid "View on %s" msgid "View on %s"
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:276 #: includes/class-archiver-admin.php:397
msgid "Warning:"
msgstr ""
#: includes/class-archiver-admin.php:326
msgid "Weekly" msgid "Weekly"
msgstr "" msgstr ""
@ -552,14 +755,14 @@ msgstr ""
msgid "WP Archiver" msgid "WP Archiver"
msgstr "" msgstr ""
#: wp-archiver.php:254 #: wp-archiver.php:256
msgid "WP Archiver requires PHP 5.6 or higher." msgid "WP Archiver requires PHP 5.6 or higher."
msgstr "" msgstr ""
#: wp-archiver.php:262 #: wp-archiver.php:264
msgid "WP Archiver requires WordPress 4.9 or higher." msgid "WP Archiver requires WordPress 4.9 or higher."
msgstr "" msgstr ""
#: includes/class-archiver-admin.php:48 #: includes/class-archiver-admin.php:75
msgid "You do not have sufficient permissions to access this page." msgid "You do not have sufficient permissions to access this page."
msgstr "" msgstr ""

View file

@ -16,13 +16,13 @@ if (!defined('ABSPATH')) {
exit; exit;
} }
// 定义常量 // Define constants
define('ARCHIVER_VERSION', '2.0.0'); define('ARCHIVER_VERSION', '2.0.0');
define('ARCHIVER_PLUGIN_DIR_URL', plugin_dir_url(__FILE__)); define('ARCHIVER_PLUGIN_DIR_URL', plugin_dir_url(__FILE__));
define('ARCHIVER_PLUGIN_DIR_PATH', plugin_dir_path(__FILE__)); define('ARCHIVER_PLUGIN_DIR_PATH', plugin_dir_path(__FILE__));
define('ARCHIVER_PLUGIN_BASENAME', plugin_basename(__FILE__)); define('ARCHIVER_PLUGIN_BASENAME', plugin_basename(__FILE__));
// 定义存档服务 - 修复原始的 wenpai.net 服务 // Define archive services
define('ARCHIVER_SERVICES', array( define('ARCHIVER_SERVICES', array(
'wayback' => array( 'wayback' => array(
'name' => 'Internet Archive', 'name' => 'Internet Archive',
@ -47,10 +47,10 @@ define('ARCHIVER_SERVICES', array(
) )
)); ));
// 插件激活 // Plugin activation
register_activation_hook(__FILE__, 'archiver_activate'); register_activation_hook(__FILE__, 'archiver_activate');
function archiver_activate() { function archiver_activate() {
// 设置默认选项 // Set default options
add_option('archiver_post_types', array('post', 'page')); add_option('archiver_post_types', array('post', 'page'));
add_option('archiver_update_frequency', 'daily'); add_option('archiver_update_frequency', 'daily');
add_option('archiver_urls_to_update', array()); add_option('archiver_urls_to_update', array());
@ -62,13 +62,13 @@ function archiver_activate() {
add_option('archiver_primary_service', 'wenpai'); add_option('archiver_primary_service', 'wenpai');
add_option('archiver_auto_archive', true); add_option('archiver_auto_archive', true);
add_option('archiver_archive_on_publish', true); add_option('archiver_archive_on_publish', true);
add_option('archiver_max_queue_size', 100); add_option('archiver_max_queue_size', 500); // Increased default
add_option('archiver_batch_size', 3); add_option('archiver_batch_size', 10); // Increased default
// 创建缓存表 // Create cache table
archiver_create_cache_table(); archiver_create_cache_table();
// 安排定时任务 // Schedule cron tasks
if (!wp_next_scheduled('archiver_process_urls')) { if (!wp_next_scheduled('archiver_process_urls')) {
wp_schedule_event(time(), 'daily', 'archiver_process_urls'); wp_schedule_event(time(), 'daily', 'archiver_process_urls');
} }
@ -77,11 +77,11 @@ function archiver_activate() {
wp_schedule_event(time(), 'daily', 'archiver_cleanup_cache'); wp_schedule_event(time(), 'daily', 'archiver_cleanup_cache');
} }
// 清理缓存 // Clear cache
wp_cache_flush(); wp_cache_flush();
} }
// 创建缓存表 // Create cache table
function archiver_create_cache_table() { function archiver_create_cache_table() {
global $wpdb; global $wpdb;
@ -111,14 +111,14 @@ function archiver_create_cache_table() {
require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql); dbDelta($sql);
// 添加索引以提高查询性能 // Add indexes for better query performance
$wpdb->query("CREATE INDEX IF NOT EXISTS idx_status_expires ON {$table_name} (status, expires_at)"); $wpdb->query("CREATE INDEX IF NOT EXISTS idx_status_expires ON {$table_name} (status, expires_at)");
} }
// 插件停用 // Plugin deactivation
register_deactivation_hook(__FILE__, 'archiver_deactivate'); register_deactivation_hook(__FILE__, 'archiver_deactivate');
function archiver_deactivate() { function archiver_deactivate() {
// 删除定时任务 // Remove scheduled tasks
$timestamp = wp_next_scheduled('archiver_process_urls'); $timestamp = wp_next_scheduled('archiver_process_urls');
if ($timestamp) { if ($timestamp) {
wp_unschedule_event($timestamp, 'archiver_process_urls'); wp_unschedule_event($timestamp, 'archiver_process_urls');
@ -129,14 +129,14 @@ function archiver_deactivate() {
wp_unschedule_event($timestamp, 'archiver_cleanup_cache'); wp_unschedule_event($timestamp, 'archiver_cleanup_cache');
} }
// 清理缓存 // Clear cache
wp_cache_flush(); wp_cache_flush();
} }
// 插件卸载 // Plugin uninstall
register_uninstall_hook(__FILE__, 'archiver_uninstall'); register_uninstall_hook(__FILE__, 'archiver_uninstall');
function archiver_uninstall() { function archiver_uninstall() {
// 删除选项 // Delete options
$options = array( $options = array(
'archiver_post_types', 'archiver_post_types',
'archiver_update_frequency', 'archiver_update_frequency',
@ -158,45 +158,46 @@ function archiver_uninstall() {
delete_option($option); delete_option($option);
} }
// 删除缓存表 // Delete cache table
global $wpdb; global $wpdb;
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}archiver_cache"); $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}archiver_cache");
// 清理所有transients // Clean all transients
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_archiver_%'"); $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_archiver_%'");
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_archiver_%'"); $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_archiver_%'");
} }
// 加载文本域 // Load text domain
add_action('init', 'archiver_load_textdomain'); add_action('init', 'archiver_load_textdomain');
function archiver_load_textdomain() { function archiver_load_textdomain() {
load_plugin_textdomain('archiver', false, dirname(plugin_basename(__FILE__)) . '/languages/'); load_plugin_textdomain('archiver', false, dirname(plugin_basename(__FILE__)) . '/languages/');
} }
// 延长 nonce 有效期(仅针对本插件) // Extend nonce life (for this plugin only)
add_filter('nonce_life', function($lifespan) { add_filter('nonce_life', function($lifespan) {
if (isset($_GET['page']) && $_GET['page'] === 'archiver-settings') { if (isset($_GET['page']) && $_GET['page'] === 'archiver-settings') {
return DAY_IN_SECONDS; // 24小时 return DAY_IN_SECONDS; // 24 hours
} }
return $lifespan; return $lifespan;
}); });
// 错误处理 // Error handling
function archiver_handle_error($message, $type = 'error') { function archiver_handle_error($message, $type = 'error') {
if (defined('WP_DEBUG') && WP_DEBUG) { if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('[WP Archiver] ' . $type . ': ' . $message); error_log('[WP Archiver] ' . $type . ': ' . $message);
} }
} }
// 加载类文件 - 注意顺序很重要! // Load class files - order is important!
function archiver_load_dependencies() { function archiver_load_dependencies() {
$includes_dir = ARCHIVER_PLUGIN_DIR_PATH . 'includes/'; $includes_dir = ARCHIVER_PLUGIN_DIR_PATH . 'includes/';
// 按正确顺序加载 // Load in correct order
$files = array( $files = array(
'class-archiver-cache.php', // 缓存类必须先加载 'class-archiver-cache.php', // Cache class must be loaded first
'class-archiver.php', // 主类 'class-archiver.php', // Main class
'class-archiver-admin.php' // 管理类最后加载 'class-archiver-admin.php', // Admin class loaded last
'class-archiver-dashboard.php' // Dashboard widget
); );
foreach ($files as $file) { foreach ($files as $file) {
@ -209,23 +210,24 @@ function archiver_load_dependencies() {
} }
} }
// 初始化插件 // Initialize plugin
add_action('plugins_loaded', 'archiver_init', 5); add_action('plugins_loaded', 'archiver_init', 5);
function archiver_init() { function archiver_init() {
// 加载依赖 // Load dependencies
archiver_load_dependencies(); archiver_load_dependencies();
// 运行插件 // Run plugin
archiver_run(); archiver_run();
} }
// 运行插件主逻辑 // Run main plugin logic
function archiver_run() { function archiver_run() {
try { try {
$archiver = Archiver::get_instance(); $archiver = Archiver::get_instance();
if (is_admin()) { if (is_admin()) {
new Archiver_Admin($archiver); new Archiver_Admin($archiver);
new Archiver_Dashboard($archiver);
} }
$archiver->run(); $archiver->run();
@ -237,7 +239,7 @@ function archiver_run() {
} }
} }
// 添加设置链接到插件列表 // Add settings link to plugin list
add_filter('plugin_action_links_' . ARCHIVER_PLUGIN_BASENAME, 'archiver_add_action_links'); add_filter('plugin_action_links_' . ARCHIVER_PLUGIN_BASENAME, 'archiver_add_action_links');
function archiver_add_action_links($links) { function archiver_add_action_links($links) {
$settings_link = '<a href="' . admin_url('tools.php?page=archiver-settings') . '">' . __('Settings', 'archiver') . '</a>'; $settings_link = '<a href="' . admin_url('tools.php?page=archiver-settings') . '">' . __('Settings', 'archiver') . '</a>';
@ -245,7 +247,7 @@ function archiver_add_action_links($links) {
return $links; return $links;
} }
// 检查系统要求 // Check system requirements
add_action('admin_init', 'archiver_check_requirements'); add_action('admin_init', 'archiver_check_requirements');
function archiver_check_requirements() { function archiver_check_requirements() {
if (version_compare(PHP_VERSION, '5.6', '<')) { if (version_compare(PHP_VERSION, '5.6', '<')) {
@ -265,17 +267,16 @@ function archiver_check_requirements() {
} }
} }
// 性能优化:限制队列大小 // Performance optimization: limit queue size
add_filter('archiver_queue_limit', function($limit) { add_filter('archiver_queue_limit', function($limit) {
return get_option('archiver_max_queue_size', 100); return get_option('archiver_max_queue_size', 500);
}); });
// 性能优化:批处理大小 // Performance optimization: batch processing size
add_filter('archiver_batch_size', function($size) { add_filter('archiver_batch_size', function($size) {
return get_option('archiver_batch_size', 3); return get_option('archiver_batch_size', 10);
}); });
// Integrate UpdatePulse Server for updates using PUC v5.3 // Integrate UpdatePulse Server for updates using PUC v5.3
require_once plugin_dir_path(__FILE__) . 'lib/plugin-update-checker/plugin-update-checker.php'; require_once plugin_dir_path(__FILE__) . 'lib/plugin-update-checker/plugin-update-checker.php';
use YahnisElsts\PluginUpdateChecker\v5p3\PucFactory; use YahnisElsts\PluginUpdateChecker\v5p3\PucFactory;