mirror of
https://github.com/WenPai-org/wp-archiver.git
synced 2025-08-18 11:51:07 +08:00
v2.0 稳定版发布
This commit is contained in:
parent
b2bd73cb85
commit
c177f340dc
14 changed files with 2979 additions and 1835 deletions
|
@ -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);
|
||||||
|
|
453
css/archiver.css
453
css/archiver.css
|
@ -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;
|
|
||||||
}
|
|
1
css/archiver.min.css
vendored
1
css/archiver.min.css
vendored
|
@ -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
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
508
includes/class-archiver-dashboard.php
Normal file
508
includes/class-archiver-dashboard.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
430
js/archiver.js
430
js/archiver.js
|
@ -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
1
js/archiver.min.js
vendored
|
@ -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.
|
@ -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 "您没有足够的权限访问此页面。"
|
||||||
|
|
|
@ -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 ""
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue