mirror of
https://github.com/WenPai-org/wp-domain-mapping.git
synced 2025-08-03 05:33:23 +08:00
优化导入导出批处理
This commit is contained in:
parent
dd5e4f04a0
commit
981ffe94ed
2 changed files with 823 additions and 344 deletions
737
admin/pages.php
737
admin/pages.php
|
@ -700,296 +700,479 @@ function dm_render_installation_check() {
|
||||||
/**
|
/**
|
||||||
* Render health tab content
|
* Render health tab content
|
||||||
*/
|
*/
|
||||||
function dm_render_health_content() {
|
function dm_render_health_content() {
|
||||||
// Get all domains
|
// Get all domains
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$tables = dm_get_table_names();
|
$tables = dm_get_table_names();
|
||||||
$domains = $wpdb->get_results("
|
$domains = $wpdb->get_results("
|
||||||
SELECT d.*, b.domain as original_domain, b.path
|
SELECT d.*, b.domain as original_domain, b.path
|
||||||
FROM {$tables['domains']} d
|
FROM {$tables['domains']} d
|
||||||
JOIN {$wpdb->blogs} b ON d.blog_id = b.blog_id
|
JOIN {$wpdb->blogs} b ON d.blog_id = b.blog_id
|
||||||
ORDER BY d.blog_id ASC, d.active DESC
|
ORDER BY d.blog_id ASC, d.active DESC
|
||||||
");
|
");
|
||||||
|
|
||||||
// Get health check results
|
// Get health check results
|
||||||
$health_results = get_site_option( 'dm_domain_health_results', array() );
|
$health_results = get_site_option( 'dm_domain_health_results', array() );
|
||||||
|
|
||||||
// Check if batch processing is in progress
|
// Check if batch processing is in progress
|
||||||
$health_check_progress = get_site_option( 'dm_health_check_progress', false );
|
$health_check_progress = get_site_option( 'dm_health_check_progress', false );
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<h2><?php _e( 'Domain Health Status', 'wp-domain-mapping' ); ?></h2>
|
<h2><?php _e( 'Domain Health Status', 'wp-domain-mapping' ); ?></h2>
|
||||||
|
|
||||||
<?php if ( $health_check_progress !== false ) : ?>
|
<?php if ( $health_check_progress !== false ) : ?>
|
||||||
<div class="notice notice-info">
|
<div class="notice notice-info">
|
||||||
<p>
|
<p>
|
||||||
<?php _e( 'Health check in progress...', 'wp-domain-mapping' ); ?>
|
<?php _e( 'Health check in progress...', 'wp-domain-mapping' ); ?>
|
||||||
<span id="health-check-progress-text">
|
<span id="health-check-progress-text">
|
||||||
<?php
|
<?php
|
||||||
printf(
|
printf(
|
||||||
__( 'Processed %d of %d domains (%d%%)', 'wp-domain-mapping' ),
|
__( 'Processed %d of %d domains (%d%%)', 'wp-domain-mapping' ),
|
||||||
$health_check_progress['processed'],
|
$health_check_progress['processed'],
|
||||||
$health_check_progress['total'],
|
$health_check_progress['total'],
|
||||||
round( ( $health_check_progress['processed'] / $health_check_progress['total'] ) * 100 )
|
$health_check_progress['total'] > 0 ? round( ( $health_check_progress['processed'] / $health_check_progress['total'] ) * 100 ) : 0
|
||||||
);
|
);
|
||||||
?>
|
?>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
<!-- 添加停止按钮 -->
|
||||||
<div class="progress-bar-outer" style="background-color: #f0f0f1; border-radius: 4px; height: 20px; width: 100%; overflow: hidden; margin-top: 10px;">
|
<button type="button" class="button button-secondary" onclick="stopHealthCheck()" style="margin-left: 15px;">
|
||||||
<div id="health-check-progress-bar" class="progress-bar-inner" style="background-color: #2271b1; height: 100%; width: <?php echo round( ( $health_check_progress['processed'] / $health_check_progress['total'] ) * 100 ); ?>%; transition: width 0.5s;"></div>
|
<?php _e( 'Stop Check', 'wp-domain-mapping' ); ?>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</p>
|
||||||
<script>
|
<div class="progress-bar-outer" style="background-color: #f0f0f1; border-radius: 4px; height: 20px; width: 100%; overflow: hidden; margin-top: 10px;">
|
||||||
jQuery(document).ready(function($) {
|
<div id="health-check-progress-bar" class="progress-bar-inner" style="background-color: #2271b1; height: 100%; width: <?php echo $health_check_progress['total'] > 0 ? round( ( $health_check_progress['processed'] / $health_check_progress['total'] ) * 100 ) : 0; ?>%; transition: width 0.5s;"></div>
|
||||||
var healthCheckInterval = setInterval(function() {
|
</div>
|
||||||
$.ajax({
|
<p style="margin-top: 10px; font-size: 12px; color: #666;">
|
||||||
url: ajaxurl,
|
<?php _e( 'This process runs in the background. You can safely leave this page.', 'wp-domain-mapping' ); ?>
|
||||||
type: 'POST',
|
</p>
|
||||||
data: {
|
</div>
|
||||||
action: 'dm_check_domain_health_batch',
|
<script>
|
||||||
nonce: '<?php echo wp_create_nonce( 'dm_check_domain_health_batch' ); ?>'
|
jQuery(document).ready(function($) {
|
||||||
},
|
var healthCheckInterval;
|
||||||
success: function(response) {
|
var maxRetries = 5;
|
||||||
if (response.success) {
|
var retryCount = 0;
|
||||||
if (response.data.complete) {
|
var isHealthCheckRunning = false;
|
||||||
clearInterval(healthCheckInterval);
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
$('#health-check-progress-text').text(
|
|
||||||
'<?php _e( 'Processed ', 'wp-domain-mapping' ); ?>' +
|
|
||||||
response.data.processed + ' <?php _e( 'of', 'wp-domain-mapping' ); ?> ' +
|
|
||||||
response.data.total + ' <?php _e( 'domains', 'wp-domain-mapping' ); ?> (' +
|
|
||||||
response.data.percentage + '%)'
|
|
||||||
);
|
|
||||||
$('#health-check-progress-bar').css('width', response.data.percentage + '%');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 2000);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<?php else : ?>
|
|
||||||
<p>
|
|
||||||
<form method="post" action="">
|
|
||||||
<?php wp_nonce_field( 'dm_manual_health_check', 'dm_manual_health_check_nonce' ); ?>
|
|
||||||
<input type="hidden" name="dm_manual_health_check" value="1">
|
|
||||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e( 'Check All Domains Now', 'wp-domain-mapping' ); ?>">
|
|
||||||
</form>
|
|
||||||
</p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<div class="tablenav top">
|
// Start monitoring health check progress
|
||||||
<div class="tablenav-pages">
|
startHealthCheckMonitoring();
|
||||||
<span class="displaying-num">
|
|
||||||
<?php
|
|
||||||
if ( ! empty( $domains ) ) {
|
|
||||||
printf(
|
|
||||||
_n( '%s domain', '%s domains', count( $domains ), 'wp-domain-mapping' ),
|
|
||||||
number_format_i18n( count( $domains ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_e( 'No domains found', 'wp-domain-mapping' );
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<br class="clear">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="wp-list-table widefat fixed striped domains-health-table">
|
/**
|
||||||
<thead>
|
* Start monitoring health check progress
|
||||||
<tr>
|
*/
|
||||||
<th class="column-domain"><?php _e( 'Domain', 'wp-domain-mapping' ); ?></th>
|
function startHealthCheckMonitoring() {
|
||||||
<th class="column-site"><?php _e( 'Site', 'wp-domain-mapping' ); ?></th>
|
if (isHealthCheckRunning) {
|
||||||
<th class="column-dns"><?php _e( 'DNS Status', 'wp-domain-mapping' ); ?></th>
|
return; // Avoid duplicate start
|
||||||
<th class="column-ssl"><?php _e( 'SSL Status', 'wp-domain-mapping' ); ?></th>
|
}
|
||||||
<th class="column-status"><?php _e( 'Reachable', 'wp-domain-mapping' ); ?></th>
|
|
||||||
<th class="column-last-check"><?php _e( 'Last Check', 'wp-domain-mapping' ); ?></th>
|
|
||||||
<th class="column-actions"><?php _e( 'Actions', 'wp-domain-mapping' ); ?></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php if ( ! empty( $domains ) ) : ?>
|
|
||||||
<?php foreach ( $domains as $domain ) :
|
|
||||||
$domain_key = md5( $domain->domain );
|
|
||||||
$health_data = isset( $health_results[$domain_key] ) ? $health_results[$domain_key] : null;
|
|
||||||
$site_name = get_blog_option( $domain->blog_id, 'blogname', __( 'Unknown', 'wp-domain-mapping' ) );
|
|
||||||
?>
|
|
||||||
<tr data-domain="<?php echo esc_attr( $domain->domain ); ?>" data-blog-id="<?php echo esc_attr( $domain->blog_id ); ?>">
|
|
||||||
<td class="column-domain">
|
|
||||||
<?php echo esc_html( $domain->domain ); ?>
|
|
||||||
<?php if ( $domain->active ) : ?>
|
|
||||||
<span class="dashicons dashicons-star-filled" style="color: #f0b849;" title="<?php esc_attr_e( 'Primary Domain', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td class="column-site">
|
|
||||||
<a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $domain->blog_id ) ); ?>">
|
|
||||||
<?php echo esc_html( $site_name ); ?>
|
|
||||||
<div class="row-actions">
|
|
||||||
<span class="original-domain"><?php echo esc_html( $domain->original_domain . $domain->path ); ?></span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="column-dns">
|
|
||||||
<?php if ( $health_data && isset( $health_data['dns_status'] ) ) : ?>
|
|
||||||
<?php if ( $health_data['dns_status'] === 'success' ) : ?>
|
|
||||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="<?php esc_attr_e( 'DNS correctly configured', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php else : ?>
|
|
||||||
<span class="dashicons dashicons-warning" style="color: #dc3232;" title="<?php echo esc_attr( $health_data['dns_message'] ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php else : ?>
|
|
||||||
<span class="dashicons dashicons-minus" style="color: #999;" title="<?php esc_attr_e( 'Not checked yet', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td class="column-ssl">
|
|
||||||
<?php if ( $health_data && isset( $health_data['ssl_valid'] ) ) : ?>
|
|
||||||
<?php if ( $health_data['ssl_valid'] ) : ?>
|
|
||||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="<?php esc_attr_e( 'SSL certificate valid', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<div class="row-actions">
|
|
||||||
<span><?php echo esc_html( sprintf( __( 'Expires: %s', 'wp-domain-mapping' ), isset( $health_data['ssl_expiry'] ) ? date( 'Y-m-d', strtotime( $health_data['ssl_expiry'] ) ) : '-' ) ); ?></span>
|
|
||||||
</div>
|
|
||||||
<?php else : ?>
|
|
||||||
<span class="dashicons dashicons-warning" style="color: #dc3232;" title="<?php esc_attr_e( 'SSL certificate issue', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php else : ?>
|
|
||||||
<span class="dashicons dashicons-minus" style="color: #999;" title="<?php esc_attr_e( 'Not checked yet', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td class="column-status">
|
|
||||||
<?php if ( $health_data && isset( $health_data['accessible'] ) ) : ?>
|
|
||||||
<?php if ( $health_data['accessible'] ) : ?>
|
|
||||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="<?php esc_attr_e( 'Site is accessible', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php else : ?>
|
|
||||||
<span class="dashicons dashicons-warning" style="color: #dc3232;" title="<?php esc_attr_e( 'Site is not accessible', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php else : ?>
|
|
||||||
<span class="dashicons dashicons-minus" style="color: #999;" title="<?php esc_attr_e( 'Not checked yet', 'wp-domain-mapping' ); ?>"></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td class="column-last-check">
|
|
||||||
<?php
|
|
||||||
if ( $health_data && isset( $health_data['last_check'] ) ) {
|
|
||||||
echo esc_html( human_time_diff( strtotime( $health_data['last_check'] ), current_time( 'timestamp' ) ) ) . ' ' . __( 'ago', 'wp-domain-mapping' );
|
|
||||||
} else {
|
|
||||||
_e( 'Never', 'wp-domain-mapping' );
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</td>
|
|
||||||
<td class="column-actions">
|
|
||||||
<button type="button" class="button button-small check-domain-health" data-domain="<?php echo esc_attr( $domain->domain ); ?>">
|
|
||||||
<?php _e( 'Check Now', 'wp-domain-mapping' ); ?>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php else : ?>
|
|
||||||
<tr>
|
|
||||||
<td colspan="7"><?php _e( 'No domains found.', 'wp-domain-mapping' ); ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php endif; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><?php _e( 'Health Check Settings', 'wp-domain-mapping' ); ?></h3>
|
isHealthCheckRunning = true;
|
||||||
|
retryCount = 0;
|
||||||
|
|
||||||
<form method="post" action="">
|
console.log('Starting health check monitoring...');
|
||||||
<?php wp_nonce_field( 'dm_health_settings', 'dm_health_settings_nonce' ); ?>
|
|
||||||
<input type="hidden" name="dm_health_settings" value="1">
|
|
||||||
|
|
||||||
<table class="form-table" role="presentation">
|
healthCheckInterval = setInterval(function() {
|
||||||
<tr>
|
checkHealthProgress();
|
||||||
<th scope="row"><?php _e( 'Automatic Health Checks', 'wp-domain-mapping' ); ?></th>
|
}, 3000); // Check every 3 seconds
|
||||||
<td>
|
|
||||||
<fieldset>
|
|
||||||
<legend class="screen-reader-text"><span><?php _e( 'Automatic Health Checks', 'wp-domain-mapping' ); ?></span></legend>
|
|
||||||
<label for="health_check_enabled">
|
|
||||||
<input name="health_check_enabled" type="checkbox" id="health_check_enabled" value="1" <?php checked( get_site_option( 'dm_health_check_enabled', true ) ); ?>>
|
|
||||||
<?php _e( 'Enable automatic daily health checks', 'wp-domain-mapping' ); ?>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row"><?php _e( 'Email Notifications', 'wp-domain-mapping' ); ?></th>
|
|
||||||
<td>
|
|
||||||
<fieldset>
|
|
||||||
<legend class="screen-reader-text"><span><?php _e( 'Email Notifications', 'wp-domain-mapping' ); ?></span></legend>
|
|
||||||
<label for="health_notifications_enabled">
|
|
||||||
<input name="health_notifications_enabled" type="checkbox" id="health_notifications_enabled" value="1" <?php checked( get_site_option( 'dm_health_notifications_enabled', true ) ); ?>>
|
|
||||||
<?php _e( 'Send email notifications when domain health issues are detected', 'wp-domain-mapping' ); ?>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row"><label for="notification_email"><?php _e( 'Notification Email', 'wp-domain-mapping' ); ?></label></th>
|
|
||||||
<td>
|
|
||||||
<input name="notification_email" type="email" id="notification_email" class="regular-text" value="<?php echo esc_attr( get_site_option( 'dm_notification_email', get_option( 'admin_email' ) ) ); ?>">
|
|
||||||
<p class="description"><?php _e( 'Email address for domain health notifications.', 'wp-domain-mapping' ); ?></p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row"><label for="ssl_expiry_threshold"><?php _e( 'SSL Expiry Warning', 'wp-domain-mapping' ); ?></label></th>
|
|
||||||
<td>
|
|
||||||
<input name="ssl_expiry_threshold" type="number" id="ssl_expiry_threshold" min="1" max="90" class="small-text" value="<?php echo esc_attr( get_site_option( 'dm_ssl_expiry_threshold', 14 ) ); ?>">
|
|
||||||
<span><?php _e( 'days', 'wp-domain-mapping' ); ?></span>
|
|
||||||
<p class="description"><?php _e( 'Send notifications when SSL certificates are expiring within this many days.', 'wp-domain-mapping' ); ?></p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row"><label for="health_check_batch_size"><?php _e( 'Batch Size', 'wp-domain-mapping' ); ?></label></th>
|
|
||||||
<td>
|
|
||||||
<input name="health_check_batch_size" type="number" id="health_check_batch_size" min="5" max="50" class="small-text" value="<?php echo esc_attr( get_site_option( 'dm_health_check_batch_size', 10 ) ); ?>">
|
|
||||||
<span><?php _e( 'domains per batch', 'wp-domain-mapping' ); ?></span>
|
|
||||||
<p class="description"><?php _e( 'Number of domains to check in each batch. Lower values prevent timeouts but take longer.', 'wp-domain-mapping' ); ?></p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p class="submit">
|
// Set maximum run time (30 minutes)
|
||||||
<input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Save Changes', 'wp-domain-mapping' ); ?>">
|
setTimeout(function() {
|
||||||
</p>
|
if (healthCheckInterval) {
|
||||||
</form>
|
stopHealthCheckMonitoring('timeout');
|
||||||
|
}
|
||||||
|
}, 1800000); // 30 minutes
|
||||||
|
}
|
||||||
|
|
||||||
<script type="text/javascript">
|
/**
|
||||||
jQuery(document).ready(function($) {
|
* Stop monitoring health check
|
||||||
// Single domain health check
|
*/
|
||||||
$('.check-domain-health').on('click', function() {
|
function stopHealthCheckMonitoring(reason) {
|
||||||
var $button = $(this);
|
if (healthCheckInterval) {
|
||||||
var domain = $button.data('domain');
|
clearInterval(healthCheckInterval);
|
||||||
var $row = $button.closest('tr');
|
healthCheckInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
$button.prop('disabled', true).text('<?php esc_html_e( 'Checking...', 'wp-domain-mapping' ); ?>');
|
isHealthCheckRunning = false;
|
||||||
|
|
||||||
$.ajax({
|
console.log('Health check monitoring stopped. Reason:', reason);
|
||||||
url: ajaxurl,
|
|
||||||
type: 'POST',
|
if (reason === 'timeout') {
|
||||||
data: {
|
showHealthCheckError('Health check timed out. Please try again.');
|
||||||
action: 'dm_check_domain_health',
|
}
|
||||||
domain: domain,
|
}
|
||||||
nonce: '<?php echo wp_create_nonce( 'dm_check_domain_health' ); ?>'
|
|
||||||
},
|
/**
|
||||||
dataType: 'json',
|
* Check health check progress
|
||||||
success: function(response) {
|
*/
|
||||||
if (response.success) {
|
function checkHealthProgress() {
|
||||||
// Refresh page to show updated results
|
$.ajax({
|
||||||
location.reload();
|
url: ajaxurl,
|
||||||
} else {
|
type: 'POST',
|
||||||
alert(response.data || '<?php esc_html_e( 'An error occurred during the health check.', 'wp-domain-mapping' ); ?>');
|
timeout: 10000, // 10 second timeout
|
||||||
$button.prop('disabled', false).text('<?php esc_html_e( 'Check Now', 'wp-domain-mapping' ); ?>');
|
data: {
|
||||||
}
|
action: 'dm_check_domain_health_batch',
|
||||||
},
|
nonce: '<?php echo wp_create_nonce( 'dm_check_domain_health_batch' ); ?>'
|
||||||
error: function() {
|
},
|
||||||
alert('<?php esc_html_e( 'An error occurred during the health check.', 'wp-domain-mapping' ); ?>');
|
success: function(response) {
|
||||||
$button.prop('disabled', false).text('<?php esc_html_e( 'Check Now', 'wp-domain-mapping' ); ?>');
|
retryCount = 0; // Reset retry count
|
||||||
}
|
|
||||||
});
|
if (response.success) {
|
||||||
});
|
var data = response.data;
|
||||||
});
|
|
||||||
</script>
|
// Update progress display
|
||||||
<?php
|
updateProgressDisplay(data);
|
||||||
}
|
|
||||||
|
if (data.complete) {
|
||||||
|
// Health check completed
|
||||||
|
stopHealthCheckMonitoring('completed');
|
||||||
|
|
||||||
|
// Delay page refresh to show results
|
||||||
|
setTimeout(function() {
|
||||||
|
window.location.href = removeUrlParameter(window.location.href, 'checking');
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('Health check error:', response.data);
|
||||||
|
handleHealthCheckError(response.data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX error:', status, error, xhr.responseText);
|
||||||
|
handleHealthCheckError('Network error: ' + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle health check error
|
||||||
|
*/
|
||||||
|
function handleHealthCheckError(errorMessage) {
|
||||||
|
retryCount++;
|
||||||
|
|
||||||
|
if (retryCount >= maxRetries) {
|
||||||
|
stopHealthCheckMonitoring('max_retries');
|
||||||
|
showHealthCheckError('Health check failed after ' + maxRetries + ' attempts: ' + errorMessage);
|
||||||
|
} else {
|
||||||
|
console.log('Health check error (attempt ' + retryCount + '/' + maxRetries + '):', errorMessage);
|
||||||
|
// Continue retrying with longer interval
|
||||||
|
clearInterval(healthCheckInterval);
|
||||||
|
healthCheckInterval = setInterval(function() {
|
||||||
|
checkHealthProgress();
|
||||||
|
}, 5000); // Extend to 5 second interval after error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update progress display
|
||||||
|
*/
|
||||||
|
function updateProgressDisplay(data) {
|
||||||
|
var percentage = data.percentage || 0;
|
||||||
|
var processed = data.processed || 0;
|
||||||
|
var total = data.total || 0;
|
||||||
|
|
||||||
|
// Update progress text
|
||||||
|
$('#health-check-progress-text').text(
|
||||||
|
'<?php _e( 'Processed ', 'wp-domain-mapping' ); ?>' +
|
||||||
|
processed + ' <?php _e( 'of', 'wp-domain-mapping' ); ?> ' +
|
||||||
|
total + ' <?php _e( 'domains', 'wp-domain-mapping' ); ?> (' +
|
||||||
|
percentage + '%)'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update progress bar
|
||||||
|
$('#health-check-progress-bar').css('width', percentage + '%');
|
||||||
|
|
||||||
|
// If there's a message, show it
|
||||||
|
if (data.message) {
|
||||||
|
console.log('Health check progress:', data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show health check error
|
||||||
|
*/
|
||||||
|
function showHealthCheckError(message) {
|
||||||
|
// Hide progress bar
|
||||||
|
$('.notice.notice-info').hide();
|
||||||
|
|
||||||
|
// Show error message
|
||||||
|
var $errorNotice = $('<div class="notice notice-error"><p><strong>Health Check Error:</strong> ' + message + '</p></div>');
|
||||||
|
$('.wrap h1').after($errorNotice);
|
||||||
|
|
||||||
|
// Auto-hide error message after 5 seconds
|
||||||
|
setTimeout(function() {
|
||||||
|
$errorNotice.fadeOut();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove parameter from URL
|
||||||
|
*/
|
||||||
|
function removeUrlParameter(url, parameter) {
|
||||||
|
var urlParts = url.split('?');
|
||||||
|
if (urlParts.length >= 2) {
|
||||||
|
var prefix = encodeURIComponent(parameter) + '=';
|
||||||
|
var params = urlParts[1].split(/[&;]/g);
|
||||||
|
|
||||||
|
for (var i = params.length; i-- > 0;) {
|
||||||
|
if (params[i].lastIndexOf(prefix, 0) !== -1) {
|
||||||
|
params.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlParts[0] + (params.length > 0 ? '?' + params.join('&') : '');
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manual stop health check
|
||||||
|
*/
|
||||||
|
window.stopHealthCheck = function() {
|
||||||
|
if (confirm('Are you sure you want to stop the health check?')) {
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxurl,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'dm_stop_health_check',
|
||||||
|
nonce: '<?php echo wp_create_nonce( 'dm_stop_health_check' ); ?>'
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
stopHealthCheckMonitoring('user_stopped');
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Clean up on page unload
|
||||||
|
$(window).on('beforeunload', function() {
|
||||||
|
if (healthCheckInterval) {
|
||||||
|
clearInterval(healthCheckInterval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php else : ?>
|
||||||
|
<p>
|
||||||
|
<form method="post" action="">
|
||||||
|
<?php wp_nonce_field( 'dm_manual_health_check', 'dm_manual_health_check_nonce' ); ?>
|
||||||
|
<input type="hidden" name="dm_manual_health_check" value="1">
|
||||||
|
<input type="submit" class="button button-primary" value="<?php esc_attr_e( 'Check All Domains Now', 'wp-domain-mapping' ); ?>">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="tablenav top">
|
||||||
|
<div class="tablenav-pages">
|
||||||
|
<span class="displaying-num">
|
||||||
|
<?php
|
||||||
|
if ( ! empty( $domains ) ) {
|
||||||
|
printf(
|
||||||
|
_n( '%s domain', '%s domains', count( $domains ), 'wp-domain-mapping' ),
|
||||||
|
number_format_i18n( count( $domains ) )
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_e( 'No domains found', 'wp-domain-mapping' );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<br class="clear">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="wp-list-table widefat fixed striped domains-health-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="column-domain"><?php _e( 'Domain', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<th class="column-site"><?php _e( 'Site', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<th class="column-dns"><?php _e( 'DNS Status', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<th class="column-ssl"><?php _e( 'SSL Status', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<th class="column-status"><?php _e( 'Reachable', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<th class="column-last-check"><?php _e( 'Last Check', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<th class="column-actions"><?php _e( 'Actions', 'wp-domain-mapping' ); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ( ! empty( $domains ) ) : ?>
|
||||||
|
<?php foreach ( $domains as $domain ) :
|
||||||
|
$domain_key = md5( $domain->domain );
|
||||||
|
$health_data = isset( $health_results[$domain_key] ) ? $health_results[$domain_key] : null;
|
||||||
|
$site_name = get_blog_option( $domain->blog_id, 'blogname', __( 'Unknown', 'wp-domain-mapping' ) );
|
||||||
|
?>
|
||||||
|
<tr data-domain="<?php echo esc_attr( $domain->domain ); ?>" data-blog-id="<?php echo esc_attr( $domain->blog_id ); ?>">
|
||||||
|
<td class="column-domain">
|
||||||
|
<?php echo esc_html( $domain->domain ); ?>
|
||||||
|
<?php if ( $domain->active ) : ?>
|
||||||
|
<span class="dashicons dashicons-star-filled" style="color: #f0b849;" title="<?php esc_attr_e( 'Primary Domain', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="column-site">
|
||||||
|
<a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $domain->blog_id ) ); ?>">
|
||||||
|
<?php echo esc_html( $site_name ); ?>
|
||||||
|
<div class="row-actions">
|
||||||
|
<span class="original-domain"><?php echo esc_html( $domain->original_domain . $domain->path ); ?></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="column-dns">
|
||||||
|
<?php if ( $health_data && isset( $health_data['dns_status'] ) ) : ?>
|
||||||
|
<?php if ( $health_data['dns_status'] === 'success' ) : ?>
|
||||||
|
<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="<?php esc_attr_e( 'DNS correctly configured', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-warning" style="color: #dc3232;" title="<?php echo esc_attr( $health_data['dns_message'] ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-minus" style="color: #999;" title="<?php esc_attr_e( 'Not checked yet', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="column-ssl">
|
||||||
|
<?php if ( $health_data && isset( $health_data['ssl_valid'] ) ) : ?>
|
||||||
|
<?php if ( $health_data['ssl_valid'] ) : ?>
|
||||||
|
<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="<?php esc_attr_e( 'SSL certificate valid', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<div class="row-actions">
|
||||||
|
<span><?php echo esc_html( sprintf( __( 'Expires: %s', 'wp-domain-mapping' ), isset( $health_data['ssl_expiry'] ) ? date( 'Y-m-d', strtotime( $health_data['ssl_expiry'] ) ) : '-' ) ); ?></span>
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-warning" style="color: #dc3232;" title="<?php esc_attr_e( 'SSL certificate issue', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-minus" style="color: #999;" title="<?php esc_attr_e( 'Not checked yet', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="column-status">
|
||||||
|
<?php if ( $health_data && isset( $health_data['accessible'] ) ) : ?>
|
||||||
|
<?php if ( $health_data['accessible'] ) : ?>
|
||||||
|
<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="<?php esc_attr_e( 'Site is accessible', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-warning" style="color: #dc3232;" title="<?php esc_attr_e( 'Site is not accessible', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="dashicons dashicons-minus" style="color: #999;" title="<?php esc_attr_e( 'Not checked yet', 'wp-domain-mapping' ); ?>"></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="column-last-check">
|
||||||
|
<?php
|
||||||
|
if ( $health_data && isset( $health_data['last_check'] ) ) {
|
||||||
|
echo esc_html( human_time_diff( strtotime( $health_data['last_check'] ), current_time( 'timestamp' ) ) ) . ' ' . __( 'ago', 'wp-domain-mapping' );
|
||||||
|
} else {
|
||||||
|
_e( 'Never', 'wp-domain-mapping' );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="column-actions">
|
||||||
|
<button type="button" class="button button-small check-domain-health" data-domain="<?php echo esc_attr( $domain->domain ); ?>">
|
||||||
|
<?php _e( 'Check Now', 'wp-domain-mapping' ); ?>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="7"><?php _e( 'No domains found.', 'wp-domain-mapping' ); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3><?php _e( 'Health Check Settings', 'wp-domain-mapping' ); ?></h3>
|
||||||
|
|
||||||
|
<form method="post" action="">
|
||||||
|
<?php wp_nonce_field( 'dm_health_settings', 'dm_health_settings_nonce' ); ?>
|
||||||
|
<input type="hidden" name="dm_health_settings" value="1">
|
||||||
|
|
||||||
|
<table class="form-table" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><?php _e( 'Automatic Health Checks', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<fieldset>
|
||||||
|
<legend class="screen-reader-text"><span><?php _e( 'Automatic Health Checks', 'wp-domain-mapping' ); ?></span></legend>
|
||||||
|
<label for="health_check_enabled">
|
||||||
|
<input name="health_check_enabled" type="checkbox" id="health_check_enabled" value="1" <?php checked( get_site_option( 'dm_health_check_enabled', true ) ); ?>>
|
||||||
|
<?php _e( 'Enable automatic daily health checks', 'wp-domain-mapping' ); ?>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><?php _e( 'Email Notifications', 'wp-domain-mapping' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<fieldset>
|
||||||
|
<legend class="screen-reader-text"><span><?php _e( 'Email Notifications', 'wp-domain-mapping' ); ?></span></legend>
|
||||||
|
<label for="health_notifications_enabled">
|
||||||
|
<input name="health_notifications_enabled" type="checkbox" id="health_notifications_enabled" value="1" <?php checked( get_site_option( 'dm_health_notifications_enabled', true ) ); ?>>
|
||||||
|
<?php _e( 'Send email notifications when domain health issues are detected', 'wp-domain-mapping' ); ?>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><label for="notification_email"><?php _e( 'Notification Email', 'wp-domain-mapping' ); ?></label></th>
|
||||||
|
<td>
|
||||||
|
<input name="notification_email" type="email" id="notification_email" class="regular-text" value="<?php echo esc_attr( get_site_option( 'dm_notification_email', get_option( 'admin_email' ) ) ); ?>">
|
||||||
|
<p class="description"><?php _e( 'Email address for domain health notifications.', 'wp-domain-mapping' ); ?></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><label for="ssl_expiry_threshold"><?php _e( 'SSL Expiry Warning', 'wp-domain-mapping' ); ?></label></th>
|
||||||
|
<td>
|
||||||
|
<input name="ssl_expiry_threshold" type="number" id="ssl_expiry_threshold" min="1" max="90" class="small-text" value="<?php echo esc_attr( get_site_option( 'dm_ssl_expiry_threshold', 14 ) ); ?>">
|
||||||
|
<span><?php _e( 'days', 'wp-domain-mapping' ); ?></span>
|
||||||
|
<p class="description"><?php _e( 'Send notifications when SSL certificates are expiring within this many days.', 'wp-domain-mapping' ); ?></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><label for="health_check_batch_size"><?php _e( 'Batch Size', 'wp-domain-mapping' ); ?></label></th>
|
||||||
|
<td>
|
||||||
|
<input name="health_check_batch_size" type="number" id="health_check_batch_size" min="3" max="20" class="small-text" value="<?php echo esc_attr( get_site_option( 'dm_health_check_batch_size', 5 ) ); ?>">
|
||||||
|
<span><?php _e( 'domains per batch', 'wp-domain-mapping' ); ?></span>
|
||||||
|
<p class="description"><?php _e( 'Number of domains to check in each batch. Lower values prevent timeouts but take longer.', 'wp-domain-mapping' ); ?></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="submit">
|
||||||
|
<input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Save Changes', 'wp-domain-mapping' ); ?>">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
// Single domain health check
|
||||||
|
$('.check-domain-health').on('click', function() {
|
||||||
|
var $button = $(this);
|
||||||
|
var domain = $button.data('domain');
|
||||||
|
var originalText = $button.text();
|
||||||
|
|
||||||
|
$button.prop('disabled', true).text('<?php esc_html_e( 'Checking...', 'wp-domain-mapping' ); ?>');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxurl,
|
||||||
|
type: 'POST',
|
||||||
|
timeout: 15000, // 15 second timeout
|
||||||
|
data: {
|
||||||
|
action: 'dm_check_domain_health',
|
||||||
|
domain: domain,
|
||||||
|
nonce: '<?php echo wp_create_nonce( 'dm_check_domain_health' ); ?>'
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
// Refresh page to show updated results
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert(response.data || '<?php esc_html_e( 'An error occurred during the health check.', 'wp-domain-mapping' ); ?>');
|
||||||
|
$button.prop('disabled', false).text(originalText);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('Single domain health check error:', status, error);
|
||||||
|
alert('<?php esc_html_e( 'An error occurred during the health check.', 'wp-domain-mapping' ); ?>');
|
||||||
|
$button.prop('disabled', false).text(originalText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if WP China Yes plugin is active
|
* Check if WP China Yes plugin is active
|
||||||
|
|
|
@ -85,10 +85,12 @@ class WP_Domain_Mapping_Tools {
|
||||||
add_action( 'wp_ajax_dm_check_domain_health', array( $this, 'ajax_check_domain_health' ) );
|
add_action( 'wp_ajax_dm_check_domain_health', array( $this, 'ajax_check_domain_health' ) );
|
||||||
add_action( 'wp_ajax_dm_check_domain_health_batch', array( $this, 'ajax_check_domain_health_batch' ) );
|
add_action( 'wp_ajax_dm_check_domain_health_batch', array( $this, 'ajax_check_domain_health_batch' ) );
|
||||||
add_action( 'wp_ajax_dm_import_csv', array( $this, 'ajax_import_csv' ) );
|
add_action( 'wp_ajax_dm_import_csv', array( $this, 'ajax_import_csv' ) );
|
||||||
|
add_action( 'wp_ajax_dm_stop_health_check', array( $this, 'ajax_stop_health_check' ) );
|
||||||
|
|
||||||
// Scheduled tasks
|
// Scheduled tasks
|
||||||
add_action( 'dm_domain_health_check', array( $this, 'scheduled_health_check' ) );
|
add_action( 'dm_domain_health_check', array( $this, 'scheduled_health_check' ) );
|
||||||
add_action( 'dm_domain_health_check_batch', array( $this, 'process_health_check_batch' ) );
|
add_action( 'dm_domain_health_check_batch', array( $this, 'process_health_check_batch' ) );
|
||||||
|
add_action( 'dm_cleanup_stuck_health_check', array( $this, 'cleanup_stuck_health_check' ) );
|
||||||
|
|
||||||
// Admin init actions
|
// Admin init actions
|
||||||
add_action( 'admin_init', array( $this, 'handle_export' ) );
|
add_action( 'admin_init', array( $this, 'handle_export' ) );
|
||||||
|
@ -102,6 +104,11 @@ class WP_Domain_Mapping_Tools {
|
||||||
if ( isset( $_GET['dm_test_cron'] ) && current_user_can( 'manage_network' ) ) {
|
if ( isset( $_GET['dm_test_cron'] ) && current_user_can( 'manage_network' ) ) {
|
||||||
add_action( 'admin_init', array( $this, 'test_cron_execution' ) );
|
add_action( 'admin_init', array( $this, 'test_cron_execution' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add cleanup hook - check for stuck health checks every hour
|
||||||
|
if ( ! wp_next_scheduled( 'dm_cleanup_stuck_health_check' ) ) {
|
||||||
|
wp_schedule_event( time(), 'hourly', 'dm_cleanup_stuck_health_check' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -332,6 +339,9 @@ class WP_Domain_Mapping_Tools {
|
||||||
// Clear batch processing health check
|
// Clear batch processing health check
|
||||||
wp_clear_scheduled_hook( 'dm_domain_health_check_batch' );
|
wp_clear_scheduled_hook( 'dm_domain_health_check_batch' );
|
||||||
|
|
||||||
|
// Clear cleanup hook
|
||||||
|
wp_clear_scheduled_hook( 'dm_cleanup_stuck_health_check' );
|
||||||
|
|
||||||
// Clear scheduling status option
|
// Clear scheduling status option
|
||||||
delete_site_option( 'dm_health_check_scheduled' );
|
delete_site_option( 'dm_health_check_scheduled' );
|
||||||
|
|
||||||
|
@ -353,11 +363,26 @@ class WP_Domain_Mapping_Tools {
|
||||||
wp_die( __( 'You do not have sufficient permissions to perform this action.', 'wp-domain-mapping' ) );
|
wp_die( __( 'You do not have sufficient permissions to perform this action.', 'wp-domain-mapping' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start batch processing
|
// Clear any existing progress data
|
||||||
$this->start_health_check_batch();
|
delete_site_option( 'dm_health_check_queue' );
|
||||||
|
delete_site_option( 'dm_health_check_progress' );
|
||||||
|
|
||||||
// Redirect back to health page
|
// Start batch processing
|
||||||
wp_redirect( add_query_arg( array( 'page' => 'domain-mapping', 'tab' => 'health', 'checking' => 1 ), network_admin_url( 'settings.php' ) ) );
|
$started = $this->start_health_check_batch();
|
||||||
|
|
||||||
|
if ( $started ) {
|
||||||
|
wp_redirect( add_query_arg( array(
|
||||||
|
'page' => 'domain-mapping',
|
||||||
|
'tab' => 'health',
|
||||||
|
'checking' => 1
|
||||||
|
), network_admin_url( 'settings.php' ) ) );
|
||||||
|
} else {
|
||||||
|
wp_redirect( add_query_arg( array(
|
||||||
|
'page' => 'domain-mapping',
|
||||||
|
'tab' => 'health',
|
||||||
|
'error' => 'no_domains'
|
||||||
|
), network_admin_url( 'settings.php' ) ) );
|
||||||
|
}
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,13 +407,13 @@ class WP_Domain_Mapping_Tools {
|
||||||
$health_notifications_enabled = isset( $_POST['health_notifications_enabled'] ) ? (bool) $_POST['health_notifications_enabled'] : false;
|
$health_notifications_enabled = isset( $_POST['health_notifications_enabled'] ) ? (bool) $_POST['health_notifications_enabled'] : false;
|
||||||
$notification_email = isset( $_POST['notification_email'] ) ? sanitize_email( $_POST['notification_email'] ) : '';
|
$notification_email = isset( $_POST['notification_email'] ) ? sanitize_email( $_POST['notification_email'] ) : '';
|
||||||
$ssl_expiry_threshold = isset( $_POST['ssl_expiry_threshold'] ) ? intval( $_POST['ssl_expiry_threshold'] ) : 14;
|
$ssl_expiry_threshold = isset( $_POST['ssl_expiry_threshold'] ) ? intval( $_POST['ssl_expiry_threshold'] ) : 14;
|
||||||
$batch_size = isset( $_POST['health_check_batch_size'] ) ? intval( $_POST['health_check_batch_size'] ) : 10;
|
$batch_size = isset( $_POST['health_check_batch_size'] ) ? intval( $_POST['health_check_batch_size'] ) : 5;
|
||||||
|
|
||||||
update_site_option( 'dm_health_check_enabled', $health_check_enabled );
|
update_site_option( 'dm_health_check_enabled', $health_check_enabled );
|
||||||
update_site_option( 'dm_health_notifications_enabled', $health_notifications_enabled );
|
update_site_option( 'dm_health_notifications_enabled', $health_notifications_enabled );
|
||||||
update_site_option( 'dm_notification_email', $notification_email );
|
update_site_option( 'dm_notification_email', $notification_email );
|
||||||
update_site_option( 'dm_ssl_expiry_threshold', $ssl_expiry_threshold );
|
update_site_option( 'dm_ssl_expiry_threshold', $ssl_expiry_threshold );
|
||||||
update_site_option( 'dm_health_check_batch_size', max( 5, min( 50, $batch_size ) ) );
|
update_site_option( 'dm_health_check_batch_size', max( 3, min( 20, $batch_size ) ) );
|
||||||
|
|
||||||
// If auto check is enabled, ensure cron is set
|
// If auto check is enabled, ensure cron is set
|
||||||
if ( $health_check_enabled ) {
|
if ( $health_check_enabled ) {
|
||||||
|
@ -468,12 +493,50 @@ class WP_Domain_Mapping_Tools {
|
||||||
wp_send_json_error( __( 'Security check failed.', 'wp-domain-mapping' ) );
|
wp_send_json_error( __( 'Security check failed.', 'wp-domain-mapping' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if there's a health check in progress
|
||||||
|
$progress = get_site_option( 'dm_health_check_progress', false );
|
||||||
|
$queue = get_site_option( 'dm_health_check_queue', array() );
|
||||||
|
|
||||||
|
if ( $progress === false && empty( $queue ) ) {
|
||||||
|
wp_send_json_success( array(
|
||||||
|
'complete' => true,
|
||||||
|
'message' => __( 'No health check in progress.', 'wp-domain-mapping' )
|
||||||
|
) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Process next batch
|
// Process next batch
|
||||||
$result = $this->process_health_check_batch( true );
|
$result = $this->process_health_check_batch( true );
|
||||||
|
|
||||||
wp_send_json_success( $result );
|
wp_send_json_success( $result );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX handler to stop health check
|
||||||
|
*/
|
||||||
|
public function ajax_stop_health_check() {
|
||||||
|
// Check permissions
|
||||||
|
if ( ! current_user_can( 'manage_network' ) ) {
|
||||||
|
wp_send_json_error( __( 'You do not have sufficient permissions to perform this action.', 'wp-domain-mapping' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify nonce
|
||||||
|
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'dm_stop_health_check' ) ) {
|
||||||
|
wp_send_json_error( __( 'Security check failed.', 'wp-domain-mapping' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear health check progress data
|
||||||
|
delete_site_option( 'dm_health_check_queue' );
|
||||||
|
delete_site_option( 'dm_health_check_progress' );
|
||||||
|
|
||||||
|
// Clear related cron tasks
|
||||||
|
wp_clear_scheduled_hook( 'dm_domain_health_check_batch' );
|
||||||
|
|
||||||
|
error_log( 'WP Domain Mapping: Health check stopped by user' );
|
||||||
|
|
||||||
|
wp_send_json_success( __( 'Health check stopped successfully.', 'wp-domain-mapping' ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scheduled health check - improved version
|
* Scheduled health check - improved version
|
||||||
*/
|
*/
|
||||||
|
@ -502,30 +565,44 @@ class WP_Domain_Mapping_Tools {
|
||||||
private function start_health_check_batch() {
|
private function start_health_check_batch() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
// Get all domains
|
// Clear any existing progress data
|
||||||
$domains = $wpdb->get_col( "SELECT domain FROM {$this->tables['domains']}" );
|
delete_site_option( 'dm_health_check_queue' );
|
||||||
|
delete_site_option( 'dm_health_check_progress' );
|
||||||
|
|
||||||
|
// Get all domains to check
|
||||||
|
$domains = array();
|
||||||
|
|
||||||
|
// Get mapped domains
|
||||||
|
$mapped_domains = $wpdb->get_col( "SELECT domain FROM {$this->tables['domains']}" );
|
||||||
|
if ( $mapped_domains ) {
|
||||||
|
$domains = array_merge( $domains, $mapped_domains );
|
||||||
|
}
|
||||||
|
|
||||||
// Add original domains for sites without mapped domains (excluding main site)
|
// Add original domains for sites without mapped domains (excluding main site)
|
||||||
$sites = get_sites( array( 'number' => 0 ) );
|
$sites = get_sites( array(
|
||||||
foreach ( $sites as $site ) {
|
'number' => 0,
|
||||||
// Skip main site
|
'site__not_in' => array( get_main_site_id() ) // Exclude main site
|
||||||
if ( is_main_site( $site->blog_id ) ) {
|
) );
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
foreach ( $sites as $site ) {
|
||||||
// Check if this site has a mapped domain
|
// Check if this site has a mapped domain
|
||||||
$has_mapped = $wpdb->get_var( $wpdb->prepare(
|
$has_mapped = $wpdb->get_var( $wpdb->prepare(
|
||||||
"SELECT COUNT(*) FROM {$this->tables['domains']} WHERE blog_id = %d",
|
"SELECT COUNT(*) FROM {$this->tables['domains']} WHERE blog_id = %d",
|
||||||
$site->blog_id
|
$site->blog_id
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// If no mapped domain, add original domain
|
||||||
if ( ! $has_mapped ) {
|
if ( ! $has_mapped ) {
|
||||||
$domains[] = $site->domain;
|
$domains[] = $site->domain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
$domains = array_unique( $domains );
|
||||||
|
|
||||||
if ( empty( $domains ) ) {
|
if ( empty( $domains ) ) {
|
||||||
return;
|
error_log( 'WP Domain Mapping: No domains found for health check' );
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store domains in queue
|
// Store domains in queue
|
||||||
|
@ -539,6 +616,9 @@ class WP_Domain_Mapping_Tools {
|
||||||
|
|
||||||
// Schedule first batch
|
// Schedule first batch
|
||||||
wp_schedule_single_event( time() + 1, 'dm_domain_health_check_batch' );
|
wp_schedule_single_event( time() + 1, 'dm_domain_health_check_batch' );
|
||||||
|
|
||||||
|
error_log( 'WP Domain Mapping: Health check batch started with ' . count( $domains ) . ' domains' );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -549,10 +629,16 @@ class WP_Domain_Mapping_Tools {
|
||||||
*/
|
*/
|
||||||
public function process_health_check_batch( $return_data = false ) {
|
public function process_health_check_batch( $return_data = false ) {
|
||||||
$queue = get_site_option( 'dm_health_check_queue', array() );
|
$queue = get_site_option( 'dm_health_check_queue', array() );
|
||||||
$progress = get_site_option( 'dm_health_check_progress', array() );
|
$progress = get_site_option( 'dm_health_check_progress', array(
|
||||||
|
'total' => 0,
|
||||||
|
'processed' => 0,
|
||||||
|
'started' => current_time( 'mysql' ),
|
||||||
|
'issues' => array()
|
||||||
|
) );
|
||||||
|
|
||||||
|
// If queue is empty, complete the process
|
||||||
if ( empty( $queue ) ) {
|
if ( empty( $queue ) ) {
|
||||||
// Batch processing complete
|
// Send notification if there are issues and notifications are enabled
|
||||||
if ( ! empty( $progress['issues'] ) && get_site_option( 'dm_health_notifications_enabled', true ) ) {
|
if ( ! empty( $progress['issues'] ) && get_site_option( 'dm_health_notifications_enabled', true ) ) {
|
||||||
$this->send_health_notification( $progress['issues'] );
|
$this->send_health_notification( $progress['issues'] );
|
||||||
}
|
}
|
||||||
|
@ -561,21 +647,26 @@ class WP_Domain_Mapping_Tools {
|
||||||
delete_site_option( 'dm_health_check_queue' );
|
delete_site_option( 'dm_health_check_queue' );
|
||||||
delete_site_option( 'dm_health_check_progress' );
|
delete_site_option( 'dm_health_check_progress' );
|
||||||
|
|
||||||
|
// Update last check time
|
||||||
|
update_site_option( 'dm_last_health_check', current_time( 'timestamp' ) );
|
||||||
|
|
||||||
if ( $return_data ) {
|
if ( $return_data ) {
|
||||||
return array(
|
return array(
|
||||||
'complete' => true,
|
'complete' => true,
|
||||||
'message' => __( 'Health check completed.', 'wp-domain-mapping' )
|
'total' => isset($progress['total']) ? $progress['total'] : 0,
|
||||||
|
'processed' => isset($progress['processed']) ? $progress['processed'] : 0,
|
||||||
|
'message' => __( 'Health check completed successfully.', 'wp-domain-mapping' )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get batch size
|
// Get batch size
|
||||||
$batch_size = get_site_option( 'dm_health_check_batch_size', 10 );
|
$batch_size = get_site_option( 'dm_health_check_batch_size', 5 ); // Reduced default batch size
|
||||||
|
|
||||||
// Process batch
|
// Process batch
|
||||||
$batch = array_splice( $queue, 0, $batch_size );
|
$batch = array_splice( $queue, 0, $batch_size );
|
||||||
$processed = 0;
|
$processed_in_batch = 0;
|
||||||
|
|
||||||
// Get main site domain to skip it
|
// Get main site domain to skip it
|
||||||
$main_site = get_site( get_main_site_id() );
|
$main_site = get_site( get_main_site_id() );
|
||||||
|
@ -584,43 +675,104 @@ class WP_Domain_Mapping_Tools {
|
||||||
foreach ( $batch as $domain ) {
|
foreach ( $batch as $domain ) {
|
||||||
// Skip main site domain
|
// Skip main site domain
|
||||||
if ( $domain === $main_domain ) {
|
if ( $domain === $main_domain ) {
|
||||||
$processed++;
|
|
||||||
$progress['processed']++;
|
$progress['processed']++;
|
||||||
|
$processed_in_batch++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->check_domain_health( $domain );
|
try {
|
||||||
dm_save_health_result( $domain, $result );
|
// Execute health check with timeout control
|
||||||
|
$start_time = microtime(true);
|
||||||
|
$result = $this->check_domain_health_with_timeout( $domain, 10 ); // 10 second timeout
|
||||||
|
$end_time = microtime(true);
|
||||||
|
|
||||||
// Check for issues
|
// Record check duration
|
||||||
if ( $this->has_health_issues( $result ) ) {
|
$result['check_duration'] = round($end_time - $start_time, 2);
|
||||||
$progress['issues'][$domain] = $result;
|
|
||||||
|
// Save result
|
||||||
|
dm_save_health_result( $domain, $result );
|
||||||
|
|
||||||
|
// Check for issues
|
||||||
|
if ( $this->has_health_issues( $result ) ) {
|
||||||
|
$progress['issues'][$domain] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch ( Exception $e ) {
|
||||||
|
// Log error but continue processing
|
||||||
|
error_log( 'WP Domain Mapping: Health check error for ' . $domain . ': ' . $e->getMessage() );
|
||||||
|
|
||||||
|
// Save error result
|
||||||
|
$error_result = array(
|
||||||
|
'domain' => $domain,
|
||||||
|
'last_check' => current_time( 'mysql' ),
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'dns_status' => 'error',
|
||||||
|
'ssl_valid' => false,
|
||||||
|
'accessible' => false
|
||||||
|
);
|
||||||
|
dm_save_health_result( $domain, $error_result );
|
||||||
}
|
}
|
||||||
|
|
||||||
$processed++;
|
|
||||||
$progress['processed']++;
|
$progress['processed']++;
|
||||||
|
$processed_in_batch++;
|
||||||
|
|
||||||
|
// Prevent memory leaks
|
||||||
|
if ( function_exists( 'wp_cache_flush' ) ) {
|
||||||
|
wp_cache_flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update queue and progress
|
// Update queue and progress
|
||||||
update_site_option( 'dm_health_check_queue', $queue );
|
update_site_option( 'dm_health_check_queue', $queue );
|
||||||
update_site_option( 'dm_health_check_progress', $progress );
|
update_site_option( 'dm_health_check_progress', $progress );
|
||||||
|
|
||||||
// Schedule next batch if needed
|
// If there are still unprocessed domains, schedule next batch
|
||||||
if ( ! empty( $queue ) && ! $return_data ) {
|
if ( ! empty( $queue ) && ! $return_data ) {
|
||||||
wp_schedule_single_event( time() + 2, 'dm_domain_health_check_batch' );
|
wp_schedule_single_event( time() + 3, 'dm_domain_health_check_batch' ); // 3 second interval
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $return_data ) {
|
if ( $return_data ) {
|
||||||
|
$remaining = count( $queue );
|
||||||
|
$percentage = $progress['total'] > 0 ? round( ( $progress['processed'] / $progress['total'] ) * 100 ) : 100;
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'complete' => empty( $queue ),
|
'complete' => empty( $queue ),
|
||||||
'total' => $progress['total'],
|
'total' => $progress['total'],
|
||||||
'processed' => $progress['processed'],
|
'processed' => $progress['processed'],
|
||||||
'remaining' => count( $queue ),
|
'remaining' => $remaining,
|
||||||
'percentage' => round( ( $progress['processed'] / $progress['total'] ) * 100 )
|
'percentage' => $percentage,
|
||||||
|
'processed_in_batch' => $processed_in_batch,
|
||||||
|
'message' => sprintf(
|
||||||
|
__( 'Processed %d of %d domains (%d%% complete)', 'wp-domain-mapping' ),
|
||||||
|
$progress['processed'],
|
||||||
|
$progress['total'],
|
||||||
|
$percentage
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain health check with timeout control
|
||||||
|
*/
|
||||||
|
private function check_domain_health_with_timeout( $domain, $timeout = 10 ) {
|
||||||
|
// Set maximum execution time
|
||||||
|
$original_time_limit = ini_get('max_execution_time');
|
||||||
|
if ( function_exists('set_time_limit') ) {
|
||||||
|
set_time_limit( $timeout + 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $this->check_domain_health( $domain );
|
||||||
|
return $result;
|
||||||
|
} finally {
|
||||||
|
// Restore original time limit
|
||||||
|
if ( function_exists('set_time_limit') && $original_time_limit ) {
|
||||||
|
set_time_limit( $original_time_limit );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check domain health
|
* Check domain health
|
||||||
*
|
*
|
||||||
|
@ -696,45 +848,64 @@ class WP_Domain_Mapping_Tools {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test domain connection
|
* Test domain connection - improved with better timeout control
|
||||||
*
|
*
|
||||||
* @param string $domain Domain to test
|
* @param string $domain Domain to test
|
||||||
* @return array|false Connection test result
|
* @return array|false Connection test result
|
||||||
*/
|
*/
|
||||||
private function test_domain_connection( $domain ) {
|
private function test_domain_connection( $domain ) {
|
||||||
if ( ! function_exists( 'curl_init' ) ) {
|
if ( ! function_exists( 'curl_init' ) ) {
|
||||||
return false;
|
return array(
|
||||||
|
'accessible' => false,
|
||||||
|
'response_code' => 0,
|
||||||
|
'ssl_valid' => false,
|
||||||
|
'ssl_expiry' => '',
|
||||||
|
'error' => 'cURL not available'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = array(
|
$result = array(
|
||||||
'accessible' => false,
|
'accessible' => false,
|
||||||
'response_code' => 0,
|
'response_code' => 0,
|
||||||
'ssl_valid' => false,
|
'ssl_valid' => false,
|
||||||
'ssl_expiry' => ''
|
'ssl_expiry' => '',
|
||||||
|
'error' => ''
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test HTTPS connection
|
// Test HTTPS connection
|
||||||
$ch = curl_init( 'https://' . $domain );
|
$ch = curl_init( 'https://' . $domain );
|
||||||
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
curl_setopt_array( $ch, array(
|
||||||
curl_setopt( $ch, CURLOPT_HEADER, true );
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
curl_setopt( $ch, CURLOPT_NOBODY, true );
|
CURLOPT_HEADER => true,
|
||||||
curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
|
CURLOPT_NOBODY => true,
|
||||||
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
|
CURLOPT_TIMEOUT => 8, // Reduced timeout
|
||||||
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
|
CURLOPT_CONNECTTIMEOUT => 5, // Connection timeout
|
||||||
curl_setopt( $ch, CURLOPT_CERTINFO, true );
|
CURLOPT_SSL_VERIFYPEER => true,
|
||||||
|
CURLOPT_SSL_VERIFYHOST => 2,
|
||||||
|
CURLOPT_CERTINFO => true,
|
||||||
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
|
CURLOPT_MAXREDIRS => 3,
|
||||||
|
CURLOPT_USERAGENT => 'WP Domain Mapping Health Check/1.0'
|
||||||
|
));
|
||||||
|
|
||||||
$response = curl_exec( $ch );
|
$response = curl_exec( $ch );
|
||||||
$response_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
|
$response_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
|
||||||
|
$ssl_error = curl_error( $ch );
|
||||||
|
|
||||||
$result['response_code'] = $response_code;
|
$result['response_code'] = $response_code;
|
||||||
|
|
||||||
if ( $response !== false && $response_code > 0 ) {
|
if ( $response !== false && $response_code > 0 ) {
|
||||||
$result['accessible'] = ( $response_code >= 200 && $response_code < 400 );
|
$result['accessible'] = ( $response_code >= 200 && $response_code < 400 );
|
||||||
$result['ssl_valid'] = ( $response !== false );
|
$result['ssl_valid'] = empty( $ssl_error );
|
||||||
|
|
||||||
// Get SSL certificate info
|
// Get SSL certificate info
|
||||||
$cert_info = curl_getinfo( $ch, CURLINFO_CERTINFO );
|
if ( $result['ssl_valid'] ) {
|
||||||
if ( ! empty( $cert_info ) && isset( $cert_info[0]['Expire date'] ) ) {
|
$cert_info = curl_getinfo( $ch, CURLINFO_CERTINFO );
|
||||||
$result['ssl_expiry'] = $cert_info[0]['Expire date'];
|
if ( ! empty( $cert_info ) && isset( $cert_info[0]['Expire date'] ) ) {
|
||||||
|
$result['ssl_expiry'] = $cert_info[0]['Expire date'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result['error'] = $ssl_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,17 +914,26 @@ class WP_Domain_Mapping_Tools {
|
||||||
// If HTTPS failed, try HTTP
|
// If HTTPS failed, try HTTP
|
||||||
if ( ! $result['accessible'] ) {
|
if ( ! $result['accessible'] ) {
|
||||||
$ch = curl_init( 'http://' . $domain );
|
$ch = curl_init( 'http://' . $domain );
|
||||||
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
curl_setopt_array( $ch, array(
|
||||||
curl_setopt( $ch, CURLOPT_HEADER, true );
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
curl_setopt( $ch, CURLOPT_NOBODY, true );
|
CURLOPT_HEADER => true,
|
||||||
curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
|
CURLOPT_NOBODY => true,
|
||||||
|
CURLOPT_TIMEOUT => 8,
|
||||||
|
CURLOPT_CONNECTTIMEOUT => 5,
|
||||||
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
|
CURLOPT_MAXREDIRS => 3,
|
||||||
|
CURLOPT_USERAGENT => 'WP Domain Mapping Health Check/1.0'
|
||||||
|
));
|
||||||
|
|
||||||
$response = curl_exec( $ch );
|
$response = curl_exec( $ch );
|
||||||
$response_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
|
$response_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
|
||||||
|
$http_error = curl_error( $ch );
|
||||||
|
|
||||||
if ( $response !== false && $response_code > 0 ) {
|
if ( $response !== false && $response_code > 0 ) {
|
||||||
$result['accessible'] = ( $response_code >= 200 && $response_code < 400 );
|
$result['accessible'] = ( $response_code >= 200 && $response_code < 400 );
|
||||||
$result['response_code'] = $response_code;
|
$result['response_code'] = $response_code;
|
||||||
|
} else {
|
||||||
|
$result['error'] = $http_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_close( $ch );
|
curl_close( $ch );
|
||||||
|
@ -864,7 +1044,30 @@ class WP_Domain_Mapping_Tools {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new method: check cron status
|
* Clean up stuck health checks
|
||||||
|
*/
|
||||||
|
public function cleanup_stuck_health_check() {
|
||||||
|
$progress = get_site_option( 'dm_health_check_progress', false );
|
||||||
|
|
||||||
|
if ( $progress !== false ) {
|
||||||
|
$started_time = strtotime( $progress['started'] );
|
||||||
|
$current_time = current_time( 'timestamp' );
|
||||||
|
|
||||||
|
// If health check running for more than 30 minutes, consider it stuck
|
||||||
|
if ( ( $current_time - $started_time ) > 1800 ) {
|
||||||
|
delete_site_option( 'dm_health_check_queue' );
|
||||||
|
delete_site_option( 'dm_health_check_progress' );
|
||||||
|
|
||||||
|
error_log( 'WP Domain Mapping: Cleaned up stuck health check that started at ' . $progress['started'] );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cron status
|
||||||
*/
|
*/
|
||||||
public function get_cron_status() {
|
public function get_cron_status() {
|
||||||
$scheduled_info = get_site_option( 'dm_health_check_scheduled', false );
|
$scheduled_info = get_site_option( 'dm_health_check_scheduled', false );
|
||||||
|
@ -995,7 +1198,7 @@ class WP_Domain_Mapping_Tools {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AJAX handler for CSV import
|
* AJAX handler for CSV import - FIXED
|
||||||
*/
|
*/
|
||||||
public function ajax_import_csv() {
|
public function ajax_import_csv() {
|
||||||
// Check permissions
|
// Check permissions
|
||||||
|
@ -1008,15 +1211,84 @@ class WP_Domain_Mapping_Tools {
|
||||||
wp_send_json_error( __( 'Invalid security token. Please try again.', 'wp-domain-mapping' ) );
|
wp_send_json_error( __( 'Invalid security token. Please try again.', 'wp-domain-mapping' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file was uploaded
|
||||||
|
if ( ! isset( $_FILES['csv_file'] ) || $_FILES['csv_file']['error'] != UPLOAD_ERR_OK ) {
|
||||||
|
wp_send_json_error( __( 'No file uploaded or upload error.', 'wp-domain-mapping' ) );
|
||||||
|
}
|
||||||
|
|
||||||
// Check file size before processing
|
// Check file size before processing
|
||||||
if ($_FILES['csv_file']['size'] > 5 * 1024 * 1024) {
|
if ($_FILES['csv_file']['size'] > 5 * 1024 * 1024) {
|
||||||
wp_send_json_error(__('File size exceeds 5MB limit.', 'wp-domain-mapping'));
|
wp_send_json_error(__('File size exceeds 5MB limit.', 'wp-domain-mapping'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check file
|
// Improved file type validation
|
||||||
if ( ! isset( $_FILES['csv_file'] ) || $_FILES['csv_file']['error'] != UPLOAD_ERR_OK ) {
|
$uploaded_filename = $_FILES['csv_file']['name'];
|
||||||
wp_send_json_error( __( 'No file uploaded or upload error.', 'wp-domain-mapping' ) );
|
$file_extension = strtolower(pathinfo($uploaded_filename, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
|
// Check file extension
|
||||||
|
if (!in_array($file_extension, array('csv', 'txt'))) {
|
||||||
|
wp_send_json_error(__('Only CSV files are allowed. File extension detected: ' . $file_extension, 'wp-domain-mapping'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional MIME type check (more reliable)
|
||||||
|
$allowed_mime_types = array(
|
||||||
|
'text/csv',
|
||||||
|
'text/plain',
|
||||||
|
'application/csv',
|
||||||
|
'application/excel',
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.msexcel'
|
||||||
|
);
|
||||||
|
|
||||||
|
$file_mime_type = '';
|
||||||
|
|
||||||
|
// Method 1: Use finfo if available (most reliable)
|
||||||
|
if (function_exists('finfo_open')) {
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
|
$file_mime_type = finfo_file($finfo, $_FILES['csv_file']['tmp_name']);
|
||||||
|
finfo_close($finfo);
|
||||||
|
}
|
||||||
|
// Method 2: Fallback to mime_content_type if available
|
||||||
|
elseif (function_exists('mime_content_type')) {
|
||||||
|
$file_mime_type = mime_content_type($_FILES['csv_file']['tmp_name']);
|
||||||
|
}
|
||||||
|
// Method 3: Use WordPress built-in function
|
||||||
|
else {
|
||||||
|
$file_type_check = wp_check_filetype_and_ext($_FILES['csv_file']['tmp_name'], $uploaded_filename);
|
||||||
|
$file_mime_type = $file_type_check['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate MIME type (but be more lenient since CSV files can have various MIME types)
|
||||||
|
if (!empty($file_mime_type) && !in_array($file_mime_type, $allowed_mime_types)) {
|
||||||
|
// Additional check: try to detect if file content looks like CSV
|
||||||
|
$file_handle = fopen($_FILES['csv_file']['tmp_name'], 'r');
|
||||||
|
if ($file_handle) {
|
||||||
|
$first_line = fgets($file_handle);
|
||||||
|
fclose($file_handle);
|
||||||
|
|
||||||
|
// Basic CSV content check - look for common CSV patterns
|
||||||
|
$csv_patterns = array(
|
||||||
|
'/,/', // Contains commas
|
||||||
|
'/;/', // Contains semicolons (common in European CSV)
|
||||||
|
'/\t/', // Contains tabs (TSV)
|
||||||
|
'/\r\n|\r|\n/' // Contains line breaks
|
||||||
|
);
|
||||||
|
|
||||||
|
$looks_like_csv = false;
|
||||||
|
foreach ($csv_patterns as $pattern) {
|
||||||
|
if (preg_match($pattern, $first_line)) {
|
||||||
|
$looks_like_csv = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$looks_like_csv) {
|
||||||
|
wp_send_json_error(__('File does not appear to be a valid CSV format. MIME type detected: ' . $file_mime_type, 'wp-domain-mapping'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get options
|
// Get options
|
||||||
|
@ -1024,19 +1296,20 @@ class WP_Domain_Mapping_Tools {
|
||||||
$update_existing = isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false;
|
$update_existing = isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false;
|
||||||
$validate_sites = isset( $_POST['validate_sites'] ) ? (bool) $_POST['validate_sites'] : true;
|
$validate_sites = isset( $_POST['validate_sites'] ) ? (bool) $_POST['validate_sites'] : true;
|
||||||
|
|
||||||
// Validate file type
|
|
||||||
$file_type = wp_check_filetype($_FILES['csv_file']['name']);
|
|
||||||
if (!in_array($file_type['ext'], array('csv', 'txt'))) {
|
|
||||||
wp_send_json_error(__('Only CSV files are allowed.', 'wp-domain-mapping'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
$file = fopen( $_FILES['csv_file']['tmp_name'], 'r' );
|
$file = fopen( $_FILES['csv_file']['tmp_name'], 'r' );
|
||||||
if ( ! $file ) {
|
if ( ! $file ) {
|
||||||
wp_send_json_error( __( 'Could not open the uploaded file.', 'wp-domain-mapping' ) );
|
wp_send_json_error( __( 'Could not open the uploaded file.', 'wp-domain-mapping' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for UTF-8 BOM and remove it
|
||||||
|
$first_bytes = fread($file, 3);
|
||||||
|
if ($first_bytes !== "\xEF\xBB\xBF") {
|
||||||
|
// If no BOM found, rewind to beginning
|
||||||
|
rewind($file);
|
||||||
|
}
|
||||||
|
// If BOM found, it's already skipped
|
||||||
|
|
||||||
// Initialize counters and log
|
// Initialize counters and log
|
||||||
$imported = 0;
|
$imported = 0;
|
||||||
$skipped = 0;
|
$skipped = 0;
|
||||||
|
@ -1048,28 +1321,42 @@ class WP_Domain_Mapping_Tools {
|
||||||
|
|
||||||
// Skip header row
|
// Skip header row
|
||||||
if ( $has_header ) {
|
if ( $has_header ) {
|
||||||
fgetcsv( $file );
|
$header_row = fgetcsv( $file );
|
||||||
|
if ($header_row === false) {
|
||||||
|
fclose($file);
|
||||||
|
wp_send_json_error(__('Could not read CSV file or file is empty.', 'wp-domain-mapping'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each row
|
// Process each row
|
||||||
$row_num = $has_header ? 2 : 1; // Account for header row
|
$row_num = $has_header ? 2 : 1; // Account for header row
|
||||||
|
$processed_rows = 0;
|
||||||
|
|
||||||
while ( ( $data = fgetcsv( $file ) ) !== false ) {
|
while ( ( $data = fgetcsv( $file ) ) !== false ) {
|
||||||
|
$processed_rows++;
|
||||||
|
|
||||||
|
// Skip empty rows
|
||||||
|
if (empty($data) || (count($data) == 1 && empty($data[0]))) {
|
||||||
|
$row_num++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check data format
|
// Check data format
|
||||||
if ( count( $data ) < 3 ) {
|
if ( count( $data ) < 3 ) {
|
||||||
$log[] = array(
|
$log[] = array(
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'message' => sprintf( __( 'Row %d: Invalid format. Expected at least 3 columns.', 'wp-domain-mapping' ), $row_num )
|
'message' => sprintf( __( 'Row %d: Invalid format. Expected at least 3 columns, got %d.', 'wp-domain-mapping' ), $row_num, count($data) )
|
||||||
);
|
);
|
||||||
$errors++;
|
$errors++;
|
||||||
$row_num++;
|
$row_num++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse data
|
// Parse data with trimming
|
||||||
$blog_id = intval( $data[0] );
|
$blog_id = intval( trim($data[0]) );
|
||||||
$domain = dm_clean_domain( trim( $data[1] ) );
|
$domain = dm_clean_domain( trim( $data[1] ) );
|
||||||
$active = intval( $data[2] );
|
$active = intval( trim($data[2]) );
|
||||||
|
|
||||||
// Check if we've already processed this domain
|
// Check if we've already processed this domain
|
||||||
if ( isset( $processed_domains[$domain] ) ) {
|
if ( isset( $processed_domains[$domain] ) ) {
|
||||||
|
@ -1178,6 +1465,14 @@ class WP_Domain_Mapping_Tools {
|
||||||
}
|
}
|
||||||
|
|
||||||
$row_num++;
|
$row_num++;
|
||||||
|
|
||||||
|
// Prevent timeout on large files
|
||||||
|
if ($processed_rows % 100 == 0) {
|
||||||
|
// Flush output and extend time limit
|
||||||
|
if (function_exists('set_time_limit')) {
|
||||||
|
set_time_limit(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose( $file );
|
fclose( $file );
|
||||||
|
@ -1193,7 +1488,8 @@ class WP_Domain_Mapping_Tools {
|
||||||
'imported' => $imported,
|
'imported' => $imported,
|
||||||
'skipped' => $skipped,
|
'skipped' => $skipped,
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'details' => $log
|
'details' => $log,
|
||||||
|
'processed_rows' => $processed_rows
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue