mirror of
https://github.com/WenPai-org/wp-domain-mapping.git
synced 2025-08-03 05:33:23 +08:00
v2.0 重构
This commit is contained in:
parent
f7fe8d63e0
commit
31bf7145ea
14 changed files with 6815 additions and 1103 deletions
514
admin/domains-page.php
Normal file
514
admin/domains-page.php
Normal file
|
@ -0,0 +1,514 @@
|
|||
<?php
|
||||
/**
|
||||
* Domains administration page
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html( get_admin_page_title() ); ?>
|
||||
<span style="font-size: 13px; padding-left: 10px;">
|
||||
<?php printf( esc_html__( 'Version: %s', 'wp-domain-mapping' ), esc_html( WP_DOMAIN_MAPPING_VERSION ) ); ?>
|
||||
</span>
|
||||
<a href="https://wpmultisite.com/document/wp-domain-mapping" target="_blank" class="button button-secondary" style="margin-left: 10px;">
|
||||
<?php esc_html_e( 'Documentation', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
<a href="https://wpmultisite.com/forums/" target="_blank" class="button button-secondary">
|
||||
<?php esc_html_e( 'Support', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php echo $edit_row ? esc_html__( 'Edit Domain', 'wp-domain-mapping' ) : esc_html__( 'Add New Domain', 'wp-domain-mapping' ); ?></h2>
|
||||
<div id="edit-domain-status" class="notice" style="display:none;"></div>
|
||||
<?php dm_edit_domain( $edit_row ); ?>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php esc_html_e( 'Search & Filter Domains', 'wp-domain-mapping' ); ?></h2>
|
||||
<form method="GET" id="domain-filter-form">
|
||||
<input type="hidden" name="page" value="domains" />
|
||||
<div class="search-form">
|
||||
<div class="search-form-field">
|
||||
<label for="domain"><?php esc_html_e( 'Domain:', 'wp-domain-mapping' ); ?></label>
|
||||
<input type="text" id="domain" name="s" value="<?php echo esc_attr( isset( $_GET['s'] ) ? $_GET['s'] : '' ); ?>" class="regular-text" placeholder="example.com" />
|
||||
</div>
|
||||
|
||||
<div class="search-form-field">
|
||||
<label for="blog_id"><?php esc_html_e( 'Site ID:', 'wp-domain-mapping' ); ?></label>
|
||||
<input type="number" id="blog_id" name="blog_id" value="<?php echo esc_attr( isset( $_GET['blog_id'] ) ? $_GET['blog_id'] : '' ); ?>" class="small-text" min="1" />
|
||||
</div>
|
||||
|
||||
<div class="search-form-field">
|
||||
<label for="active"><?php esc_html_e( 'Primary:', 'wp-domain-mapping' ); ?></label>
|
||||
<select id="active" name="active">
|
||||
<option value=""><?php esc_html_e( 'All', 'wp-domain-mapping' ); ?></option>
|
||||
<option value="1" <?php selected( isset( $_GET['active'] ) && $_GET['active'] == '1' ); ?>>
|
||||
<?php esc_html_e( 'Yes', 'wp-domain-mapping' ); ?>
|
||||
</option>
|
||||
<option value="0" <?php selected( isset( $_GET['active'] ) && $_GET['active'] == '0' ); ?>>
|
||||
<?php esc_html_e( 'No', 'wp-domain-mapping' ); ?>
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="search-form-submit">
|
||||
<input type="submit" class="button button-secondary" value="<?php esc_attr_e( 'Filter', 'wp-domain-mapping' ); ?>" />
|
||||
<?php if ( isset( $_GET['s'] ) || isset( $_GET['blog_id'] ) || isset( $_GET['active'] ) ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'network/sites.php?page=domains' ) ); ?>" class="button button-link">
|
||||
<?php esc_html_e( 'Clear', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<div class="domain-mapping-tabs">
|
||||
<button type="button" class="domain-mapping-tab active" data-tab="manage-domains">
|
||||
<?php esc_html_e( 'Manage Domains', 'wp-domain-mapping' ); ?>
|
||||
</button>
|
||||
<button type="button" class="domain-mapping-tab" data-tab="domain-logs">
|
||||
<?php esc_html_e( 'Domain Logs', 'wp-domain-mapping' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="domain-mapping-content">
|
||||
<div class="domain-mapping-section" data-section="manage-domains">
|
||||
<div id="domain-status" class="notice" style="display:none;"></div>
|
||||
<form id="domain-list-form" method="POST">
|
||||
<?php
|
||||
$per_page = isset( $_GET['per_page'] ) ? absint( $_GET['per_page'] ) : 20;
|
||||
$paged = isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
|
||||
$offset = ( $paged - 1 ) * $per_page;
|
||||
|
||||
// Build the WHERE clause for filtering
|
||||
$where = array();
|
||||
if ( ! empty( $_GET['s'] ) ) {
|
||||
$where[] = $wpdb->prepare(
|
||||
"domain LIKE %s",
|
||||
'%' . $wpdb->esc_like( sanitize_text_field( $_GET['s'] ) ) . '%'
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $_GET['blog_id'] ) ) {
|
||||
$where[] = $wpdb->prepare(
|
||||
"blog_id = %d",
|
||||
absint( $_GET['blog_id'] )
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $_GET['active'] ) && $_GET['active'] !== '' ) {
|
||||
$where[] = $wpdb->prepare(
|
||||
"active = %d",
|
||||
absint( $_GET['active'] )
|
||||
);
|
||||
}
|
||||
|
||||
$where_sql = $where ? ' WHERE ' . implode( ' AND ', $where ) : '';
|
||||
|
||||
// Count total items for pagination
|
||||
$total_items = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->base_prefix}" . WP_DOMAIN_MAPPING_TABLE_DOMAINS . $where_sql );
|
||||
$total_pages = ceil( $total_items / $per_page );
|
||||
|
||||
// Get the domains with pagination
|
||||
$rows = $wpdb->get_results( $wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->base_prefix}" . WP_DOMAIN_MAPPING_TABLE_DOMAINS . $where_sql . " ORDER BY id DESC LIMIT %d, %d",
|
||||
$offset,
|
||||
$per_page
|
||||
));
|
||||
|
||||
// Display the domains table
|
||||
dm_domain_listing( $rows );
|
||||
|
||||
// Pagination
|
||||
if ( $total_pages > 1 ) :
|
||||
?>
|
||||
<div class="tablenav bottom">
|
||||
<div class="tablenav-pages">
|
||||
<?php
|
||||
echo paginate_links( array(
|
||||
'base' => add_query_arg( 'paged', '%#%' ),
|
||||
'format' => '',
|
||||
'prev_text' => __( '«' ),
|
||||
'next_text' => __( '»' ),
|
||||
'total' => $total_pages,
|
||||
'current' => $paged,
|
||||
'mid_size' => 2,
|
||||
'end_size' => 1,
|
||||
) );
|
||||
?>
|
||||
<span class="displaying-num">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: number of items */
|
||||
_n( '%s item', '%s items', $total_items, 'wp-domain-mapping' ),
|
||||
number_format_i18n( $total_items )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: IDN warning message */
|
||||
__( '<strong>Note:</strong> %s', 'wp-domain-mapping' ),
|
||||
dm_idn_warning()
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="domain-mapping-section" data-section="domain-logs" style="display:none;">
|
||||
<?php dm_domain_logs(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php esc_html_e( 'Domain Statistics', 'wp-domain-mapping' ); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Total Domains', 'wp-domain-mapping' ); ?></th>
|
||||
<td><?php echo esc_html( $total_domains ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Primary Domains', 'wp-domain-mapping' ); ?></th>
|
||||
<td><?php echo esc_html( $primary_domains ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Sites with Mapped Domains', 'wp-domain-mapping' ); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
$sites_with_domains = $wpdb->get_var( "SELECT COUNT(DISTINCT blog_id) FROM {$wpdb->base_prefix}" . WP_DOMAIN_MAPPING_TABLE_DOMAINS );
|
||||
echo esc_html( $sites_with_domains );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
// Tab switching functionality
|
||||
$('.domain-mapping-tab').on('click', function() {
|
||||
$('.domain-mapping-tab').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
var tab = $(this).data('tab');
|
||||
$('.domain-mapping-section').hide();
|
||||
$('.domain-mapping-section[data-section="' + tab + '"]').show();
|
||||
});
|
||||
|
||||
// Helper function for showing notices
|
||||
function showNotice(selector, message, type) {
|
||||
$(selector)
|
||||
.removeClass('notice-success notice-error notice-warning notice-info')
|
||||
.addClass('notice-' + type)
|
||||
.html('<p>' + message + '</p>')
|
||||
.show()
|
||||
.delay(3000)
|
||||
.fadeOut();
|
||||
}
|
||||
|
||||
// Handle domain edit/add form submission
|
||||
$('#edit-domain-form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Validate form
|
||||
var blogId = $('#blog_id').val();
|
||||
var domain = $('#domain').val();
|
||||
|
||||
if (!blogId || !domain) {
|
||||
showNotice('#edit-domain-status', '<?php esc_html_e( 'Please fill in all required fields.', 'wp-domain-mapping' ); ?>', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = $(this).serializeArray();
|
||||
formData.push({name: 'action', value: 'dm_handle_actions'});
|
||||
formData.push({name: 'action_type', value: 'save'});
|
||||
formData.push({name: 'nonce', value: '<?php echo wp_create_nonce( 'domain_mapping' ); ?>'});
|
||||
|
||||
$('#edit-domain-status').html('<p><?php esc_html_e( 'Saving...', 'wp-domain-mapping' ); ?></p>').show();
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showNotice('#edit-domain-status', response.data, 'success');
|
||||
setTimeout(function() {
|
||||
location.href = '<?php echo esc_js( admin_url( 'network/sites.php?page=domains' ) ); ?>';
|
||||
}, 1000);
|
||||
} else {
|
||||
showNotice('#edit-domain-status', response.data || '<?php esc_html_e( 'Failed to save domain.', 'wp-domain-mapping' ); ?>', 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showNotice('#edit-domain-status', '<?php esc_html_e( 'Server error occurred.', 'wp-domain-mapping' ); ?>', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle domain list bulk actions
|
||||
$('#domain-list-form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var selectedDomains = [];
|
||||
$('.domain-checkbox:checked').each(function() {
|
||||
selectedDomains.push($(this).val());
|
||||
});
|
||||
|
||||
if (selectedDomains.length === 0) {
|
||||
showNotice('#domain-status', '<?php esc_html_e( 'Please select at least one domain.', 'wp-domain-mapping' ); ?>', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
var action = $('#bulk-action-selector-top').val();
|
||||
if (action === '-1') return;
|
||||
|
||||
if (!confirm('<?php esc_html_e( 'Are you sure you want to delete the selected domains?', 'wp-domain-mapping' ); ?>')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#domain-status').html('<p><?php esc_html_e( 'Processing...', 'wp-domain-mapping' ); ?></p>').show();
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'dm_handle_actions',
|
||||
action_type: 'delete',
|
||||
domains: selectedDomains,
|
||||
nonce: '<?php echo wp_create_nonce( 'domain_mapping' ); ?>'
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showNotice('#domain-status', response.data, 'success');
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
showNotice('#domain-status', response.data || '<?php esc_html_e( 'Failed to delete domains.', 'wp-domain-mapping' ); ?>', 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showNotice('#domain-status', '<?php esc_html_e( 'Server error occurred.', 'wp-domain-mapping' ); ?>', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Main cards */
|
||||
.domain-mapping-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ccd0d4;
|
||||
border-radius: 4px;
|
||||
max-width: unset;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.domain-mapping-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
border-bottom: 1px solid #c3c4c7;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.domain-mapping-tab {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.domain-mapping-tab.active {
|
||||
border-bottom: 2px solid #007cba;
|
||||
font-weight: 600;
|
||||
background: #f0f0f1;
|
||||
}
|
||||
|
||||
.domain-mapping-tab:hover:not(.active) {
|
||||
background: #f0f0f1;
|
||||
border-bottom-color: #dcdcde;
|
||||
}
|
||||
|
||||
.domain-mapping-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Search form */
|
||||
.search-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.search-form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.search-form-field label {
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.search-form-submit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.tablenav {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tablenav-pages {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.tablenav-pages a,
|
||||
.tablenav-pages span.current {
|
||||
display: inline-block;
|
||||
min-width: 17px;
|
||||
padding: 3px 5px 7px;
|
||||
background: #f0f0f1;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tablenav-pages span.current {
|
||||
background: #007cba;
|
||||
color: #fff;
|
||||
border-color: #007cba;
|
||||
}
|
||||
|
||||
.displaying-num {
|
||||
margin-left: 10px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.domains-table th,
|
||||
.logs-table th {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.column-site-id {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.column-site-name {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.column-primary {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.column-actions {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
/* Form elements */
|
||||
.form-table th {
|
||||
width: 200px;
|
||||
padding: 15px 10px 15px 0;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Notices */
|
||||
.notice {
|
||||
padding: 8px 12px;
|
||||
border-radius: 3px;
|
||||
margin: 5px 0 15px;
|
||||
}
|
||||
|
||||
.notice p {
|
||||
margin: 0.5em 0;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.notice-success {
|
||||
background-color: #f0f9eb;
|
||||
border-left: 4px solid #46b450;
|
||||
}
|
||||
|
||||
.notice-error {
|
||||
background-color: #fef0f0;
|
||||
border-left: 4px solid #dc3232;
|
||||
}
|
||||
|
||||
.notice-warning {
|
||||
background-color: #fff8e5;
|
||||
border-left: 4px solid #ffb900;
|
||||
}
|
||||
|
||||
.notice-info {
|
||||
background-color: #f0f6fa;
|
||||
border-left: 4px solid #00a0d2;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media screen and (max-width: 782px) {
|
||||
.search-form {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.search-form-field {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.form-table th {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
display: block;
|
||||
padding: 0 0 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
288
admin/logs-table.php
Normal file
288
admin/logs-table.php
Normal file
|
@ -0,0 +1,288 @@
|
|||
<?php
|
||||
/**
|
||||
* Logs table display for domain mapping
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get pagination parameters
|
||||
$per_page = isset( $_GET['logs_per_page'] ) ? absint( $_GET['logs_per_page'] ) : 50;
|
||||
$paged = isset( $_GET['logs_paged'] ) ? absint( $_GET['logs_paged'] ) : 1;
|
||||
$offset = ( $paged - 1 ) * $per_page;
|
||||
|
||||
// Get action filter
|
||||
$action_filter = isset( $_GET['log_action'] ) ? sanitize_text_field( $_GET['log_action'] ) : '';
|
||||
|
||||
// Build WHERE clause for filtering
|
||||
$where = array();
|
||||
if ( ! empty( $action_filter ) ) {
|
||||
$where[] = $wpdb->prepare( "action = %s", $action_filter );
|
||||
}
|
||||
|
||||
$where_sql = $where ? ' WHERE ' . implode( ' AND ', $where ) : '';
|
||||
|
||||
// Count total logs for pagination
|
||||
$total_logs = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->base_prefix}" . WP_DOMAIN_MAPPING_TABLE_LOGS . $where_sql );
|
||||
$total_pages = ceil( $total_logs / $per_page );
|
||||
|
||||
// Get logs with pagination
|
||||
$logs = $wpdb->get_results( $wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->base_prefix}" . WP_DOMAIN_MAPPING_TABLE_LOGS . $where_sql . " ORDER BY timestamp DESC LIMIT %d, %d",
|
||||
$offset,
|
||||
$per_page
|
||||
));
|
||||
|
||||
// Get available actions for filter
|
||||
$actions = $wpdb->get_col( "SELECT DISTINCT action FROM {$wpdb->base_prefix}" . WP_DOMAIN_MAPPING_TABLE_LOGS );
|
||||
|
||||
if ( ! $logs ) {
|
||||
echo '<div class="notice notice-info"><p>' . esc_html__( 'No domain mapping logs available.', 'wp-domain-mapping' ) . '</p></div>';
|
||||
return;
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="tablenav top">
|
||||
<form method="GET" id="logs-filter-form" class="logs-filter">
|
||||
<input type="hidden" name="page" value="domains" />
|
||||
<input type="hidden" name="tab" value="domain-logs" />
|
||||
|
||||
<div class="alignleft actions">
|
||||
<label for="log_action" class="screen-reader-text"><?php esc_html_e( 'Filter by action', 'wp-domain-mapping' ); ?></label>
|
||||
<select id="log_action" name="log_action">
|
||||
<option value=""><?php esc_html_e( 'All actions', 'wp-domain-mapping' ); ?></option>
|
||||
<?php foreach ( $actions as $action ) : ?>
|
||||
<option value="<?php echo esc_attr( $action ); ?>" <?php selected( $action_filter, $action ); ?>>
|
||||
<?php
|
||||
switch ( $action ) {
|
||||
case 'add':
|
||||
esc_html_e( 'Added', 'wp-domain-mapping' );
|
||||
break;
|
||||
case 'edit':
|
||||
esc_html_e( 'Updated', 'wp-domain-mapping' );
|
||||
break;
|
||||
case 'delete':
|
||||
esc_html_e( 'Deleted', 'wp-domain-mapping' );
|
||||
break;
|
||||
default:
|
||||
echo esc_html( ucfirst( $action ) );
|
||||
}
|
||||
?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
|
||||
<input type="submit" class="button" value="<?php esc_attr_e( 'Filter', 'wp-domain-mapping' ); ?>" />
|
||||
|
||||
<?php if ( ! empty( $action_filter ) ) : ?>
|
||||
<a href="<?php echo esc_url( add_query_arg( array( 'page' => 'domains', 'tab' => 'domain-logs' ), admin_url( 'network/sites.php' ) ) ); ?>" class="button">
|
||||
<?php esc_html_e( 'Clear', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php if ( $total_pages > 1 ) : ?>
|
||||
<div class="tablenav-pages">
|
||||
<?php
|
||||
echo paginate_links( array(
|
||||
'base' => add_query_arg( 'logs_paged', '%#%' ),
|
||||
'format' => '',
|
||||
'prev_text' => __( '«' ),
|
||||
'next_text' => __( '»' ),
|
||||
'total' => $total_pages,
|
||||
'current' => $paged,
|
||||
'mid_size' => 2,
|
||||
'end_size' => 1,
|
||||
) );
|
||||
?>
|
||||
<span class="displaying-num">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: number of items */
|
||||
_n( '%s log entry', '%s log entries', $total_logs, 'wp-domain-mapping' ),
|
||||
number_format_i18n( $total_logs )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<table class="wp-list-table widefat striped logs-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="column-user"><?php esc_html_e( 'User', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-action"><?php esc_html_e( 'Action', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-domain"><?php esc_html_e( 'Domain', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-site"><?php esc_html_e( 'Site', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-date"><?php esc_html_e( 'Date', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $logs as $log ) :
|
||||
// Get user data
|
||||
$user_data = get_userdata( $log->user_id );
|
||||
$username = $user_data
|
||||
? sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( network_admin_url( 'user-edit.php?user_id=' . $log->user_id ) ),
|
||||
esc_html( $user_data->user_login )
|
||||
)
|
||||
: sprintf( esc_html__( 'User #%d', 'wp-domain-mapping' ), $log->user_id );
|
||||
|
||||
// Format action for display
|
||||
switch ( $log->action ) {
|
||||
case 'add':
|
||||
$action_display = '<span class="log-action log-action-add">' . esc_html__( 'Added', 'wp-domain-mapping' ) . '</span>';
|
||||
break;
|
||||
case 'edit':
|
||||
$action_display = '<span class="log-action log-action-edit">' . esc_html__( 'Updated', 'wp-domain-mapping' ) . '</span>';
|
||||
break;
|
||||
case 'delete':
|
||||
$action_display = '<span class="log-action log-action-delete">' . esc_html__( 'Deleted', 'wp-domain-mapping' ) . '</span>';
|
||||
break;
|
||||
default:
|
||||
$action_display = '<span class="log-action">' . esc_html( ucfirst( $log->action ) ) . '</span>';
|
||||
}
|
||||
|
||||
// Get site name
|
||||
$site_name = get_blog_option( $log->blog_id, 'blogname', '' );
|
||||
$site_link = ! empty( $site_name )
|
||||
? sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( network_admin_url( 'site-info.php?id=' . $log->blog_id ) ),
|
||||
esc_html( $site_name )
|
||||
)
|
||||
: sprintf( esc_html__( 'Site #%d', 'wp-domain-mapping' ), $log->blog_id );
|
||||
|
||||
// Format timestamp for display
|
||||
$timestamp = mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $log->timestamp );
|
||||
$time_diff = human_time_diff( strtotime( $log->timestamp ), current_time( 'timestamp' ) );
|
||||
?>
|
||||
<tr>
|
||||
<td class="column-user"><?php echo $username; ?></td>
|
||||
<td class="column-action"><?php echo $action_display; ?></td>
|
||||
<td class="column-domain">
|
||||
<a href="<?php echo esc_url( dm_ensure_protocol( $log->domain ) ); ?>" target="_blank">
|
||||
<?php echo esc_html( $log->domain ); ?>
|
||||
<span class="dashicons dashicons-external" style="font-size: 14px; line-height: 1.3; opacity: 0.7;"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td class="column-site">
|
||||
<?php echo $site_link; ?>
|
||||
</td>
|
||||
<td class="column-date">
|
||||
<abbr title="<?php echo esc_attr( $timestamp ); ?>">
|
||||
<?php
|
||||
/* translators: %s: time ago */
|
||||
printf( esc_html__( '%s ago', 'wp-domain-mapping' ), $time_diff );
|
||||
?>
|
||||
</abbr>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php if ( $total_pages > 1 ) : ?>
|
||||
<div class="tablenav bottom">
|
||||
<div class="tablenav-pages">
|
||||
<?php
|
||||
echo paginate_links( array(
|
||||
'base' => add_query_arg( 'logs_paged', '%#%' ),
|
||||
'format' => '',
|
||||
'prev_text' => __( '«' ),
|
||||
'next_text' => __( '»' ),
|
||||
'total' => $total_pages,
|
||||
'current' => $paged,
|
||||
'mid_size' => 2,
|
||||
'end_size' => 1,
|
||||
) );
|
||||
?>
|
||||
<span class="displaying-num">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: number of items */
|
||||
_n( '%s log entry', '%s log entries', $total_logs, 'wp-domain-mapping' ),
|
||||
number_format_i18n( $total_logs )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<style>
|
||||
/* Logs table styles */
|
||||
.logs-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.logs-table .column-user,
|
||||
.logs-table .column-site {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.logs-table .column-action {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.logs-table .column-date {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.log-action {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.log-action-add {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
}
|
||||
|
||||
.log-action-edit {
|
||||
background-color: #d9edf7;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
.log-action-delete {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
.tablenav-pages a,
|
||||
.tablenav-pages span.current {
|
||||
display: inline-block;
|
||||
min-width: 17px;
|
||||
padding: 3px 5px 7px;
|
||||
background: #f0f0f1;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tablenav-pages span.current {
|
||||
background: #007cba;
|
||||
color: #fff;
|
||||
border-color: #007cba;
|
||||
}
|
||||
|
||||
.displaying-num {
|
||||
margin-left: 10px;
|
||||
color: #555;
|
||||
}
|
||||
</style>
|
522
admin/settings-page.php
Normal file
522
admin/settings-page.php
Normal file
|
@ -0,0 +1,522 @@
|
|||
<?php
|
||||
/**
|
||||
* Settings administration page
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get current options
|
||||
$dm_ipaddress = get_site_option( 'dm_ipaddress', '' );
|
||||
$dm_cname = get_site_option( 'dm_cname', '' );
|
||||
$dm_remote_login = get_site_option( 'dm_remote_login', 1 );
|
||||
$dm_301_redirect = get_site_option( 'dm_301_redirect', 0 );
|
||||
$dm_redirect_admin = get_site_option( 'dm_redirect_admin', 1 );
|
||||
$dm_user_settings = get_site_option( 'dm_user_settings', 1 );
|
||||
$dm_no_primary_domain = get_site_option( 'dm_no_primary_domain', 0 );
|
||||
|
||||
// Get server IP address if not set
|
||||
if ( empty( $dm_ipaddress ) ) {
|
||||
$server_ip = isset( $_SERVER['SERVER_ADDR'] ) ? $_SERVER['SERVER_ADDR'] : '';
|
||||
if ( empty( $server_ip ) && function_exists( 'gethostbyname' ) ) {
|
||||
$server_ip = gethostbyname( $_SERVER['SERVER_NAME'] );
|
||||
}
|
||||
if ( $server_ip && filter_var( $server_ip, FILTER_VALIDATE_IP ) ) {
|
||||
$dm_ipaddress = $server_ip;
|
||||
}
|
||||
}
|
||||
|
||||
// Display settings errors
|
||||
settings_errors( 'dm_settings' );
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html( get_admin_page_title() ); ?>
|
||||
<span style="font-size: 13px; padding-left: 10px;">
|
||||
<?php printf( esc_html__( 'Version: %s', 'wp-domain-mapping' ), esc_html( WP_DOMAIN_MAPPING_VERSION ) ); ?>
|
||||
</span>
|
||||
<a href="https://wpmultisite.com/document/wp-domain-mapping" target="_blank" class="button button-secondary" style="margin-left: 10px;">
|
||||
<?php esc_html_e( 'Documentation', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
<a href="https://wpmultisite.com/forums/" target="_blank" class="button button-secondary">
|
||||
<?php esc_html_e( 'Support', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="update" />
|
||||
<?php wp_nonce_field( 'domain_mapping' ); ?>
|
||||
|
||||
<h2><?php esc_html_e( 'Server Configuration', 'wp-domain-mapping' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Configure the IP address or CNAME for domain mapping.', 'wp-domain-mapping' ); ?></p>
|
||||
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row"><label for="ipaddress"><?php esc_html_e( 'Server IP Address:', 'wp-domain-mapping' ); ?></label></th>
|
||||
<td>
|
||||
<input type="text" id="ipaddress" name="ipaddress" value="<?php echo esc_attr( $dm_ipaddress ); ?>" class="regular-text" />
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Enter the IP address(es) users should point their DNS A records to. Use commas to separate multiple IPs.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
<?php if ( ! empty( $server_ip ) && $server_ip != $dm_ipaddress ) : ?>
|
||||
<p class="description">
|
||||
<?php printf(
|
||||
/* translators: %s: Server IP address */
|
||||
esc_html__( 'Detected server IP: %s', 'wp-domain-mapping' ),
|
||||
'<code>' . esc_html( $server_ip ) . '</code>'
|
||||
); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="cname"><?php esc_html_e( 'Server CNAME Domain:', 'wp-domain-mapping' ); ?></label></th>
|
||||
<td>
|
||||
<input type="text" id="cname" name="cname" value="<?php echo esc_attr( $dm_cname ); ?>" class="regular-text" placeholder="server.example.com" />
|
||||
<p class="description">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: IDN warning message */
|
||||
esc_html__( 'Use a CNAME instead of an IP (overrides IP settings). %s', 'wp-domain-mapping' ),
|
||||
dm_idn_warning()
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3><?php esc_html_e( 'Domain Options', 'wp-domain-mapping' ); ?></h3>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php esc_html_e( 'Domain Options', 'wp-domain-mapping' ); ?></legend>
|
||||
<label for="dm_remote_login">
|
||||
<input type="checkbox" name="dm_remote_login" id="dm_remote_login" value="1" <?php checked( $dm_remote_login, 1 ); ?> />
|
||||
<?php esc_html_e( 'Enable Remote Login', 'wp-domain-mapping' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Allows users to log in from mapped domains and be redirected to the original domain for authentication.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php esc_html_e( 'Permanent Redirect', 'wp-domain-mapping' ); ?></legend>
|
||||
<label for="permanent_redirect">
|
||||
<input type="checkbox" name="permanent_redirect" id="permanent_redirect" value="1" <?php checked( $dm_301_redirect, 1 ); ?> />
|
||||
<?php esc_html_e( 'Use Permanent Redirect (301)', 'wp-domain-mapping' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Use 301 redirects instead of 302 redirects. This is better for SEO but may cause caching issues.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php esc_html_e( 'User Settings', 'wp-domain-mapping' ); ?></legend>
|
||||
<label for="dm_user_settings">
|
||||
<input type="checkbox" name="dm_user_settings" id="dm_user_settings" value="1" <?php checked( $dm_user_settings, 1 ); ?> />
|
||||
<?php esc_html_e( 'Enable User Domain Mapping Page', 'wp-domain-mapping' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Allow site administrators to manage their domain mappings from the Tools menu.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php esc_html_e( 'Redirect Admin', 'wp-domain-mapping' ); ?></legend>
|
||||
<label for="always_redirect_admin">
|
||||
<input type="checkbox" name="always_redirect_admin" id="always_redirect_admin" value="1" <?php checked( $dm_redirect_admin, 1 ); ?> />
|
||||
<?php esc_html_e( 'Redirect Admin Pages to Original Domain', 'wp-domain-mapping' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Force admin pages to use the original WordPress domain instead of the mapped domain.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php esc_html_e( 'Disable Primary Domain', 'wp-domain-mapping' ); ?></legend>
|
||||
<label for="dm_no_primary_domain">
|
||||
<input type="checkbox" name="dm_no_primary_domain" id="dm_no_primary_domain" value="1" <?php checked( $dm_no_primary_domain, 1 ); ?> />
|
||||
<?php esc_html_e( 'Disable Primary Domain Check', 'wp-domain-mapping' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Do not redirect to the primary domain, but allow access through any mapped domain.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="submit">
|
||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e( 'Save Configuration', 'wp-domain-mapping' ); ?>" />
|
||||
<a href="<?php echo esc_url( admin_url( 'network/sites.php?page=domains' ) ); ?>" class="button button-secondary">
|
||||
<?php esc_html_e( 'Manage Domains', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php esc_html_e( 'DNS Setup Instructions', 'wp-domain-mapping' ); ?></h2>
|
||||
|
||||
<div class="dns-instructions">
|
||||
<?php if ( ! empty( $dm_cname ) ) : ?>
|
||||
<h3><?php esc_html_e( 'CNAME Method (Recommended)', 'wp-domain-mapping' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: CNAME value */
|
||||
esc_html__( 'Tell your users to add a DNS "CNAME" record for their domain pointing to: %s', 'wp-domain-mapping' ),
|
||||
'<code>' . esc_html( $dm_cname ) . '</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<div class="dns-example">
|
||||
<h4><?php esc_html_e( 'Example DNS Record', 'wp-domain-mapping' ); ?></h4>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Type', 'wp-domain-mapping' ); ?></th>
|
||||
<th><?php esc_html_e( 'Name', 'wp-domain-mapping' ); ?></th>
|
||||
<th><?php esc_html_e( 'Value', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>CNAME</code></td>
|
||||
<td><code>@</code> <?php esc_html_e( '(or empty)', 'wp-domain-mapping' ); ?></td>
|
||||
<td><code><?php echo esc_html( $dm_cname ); ?></code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $dm_ipaddress ) ) : ?>
|
||||
<h3><?php esc_html_e( 'A Record Method', 'wp-domain-mapping' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: IP address(es) */
|
||||
esc_html__( 'Tell your users to add a DNS "A" record for their domain pointing to: %s', 'wp-domain-mapping' ),
|
||||
'<code>' . esc_html( $dm_ipaddress ) . '</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<div class="dns-example">
|
||||
<h4><?php esc_html_e( 'Example DNS Record', 'wp-domain-mapping' ); ?></h4>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Type', 'wp-domain-mapping' ); ?></th>
|
||||
<th><?php esc_html_e( 'Name', 'wp-domain-mapping' ); ?></th>
|
||||
<th><?php esc_html_e( 'Value', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$ips = array_map( 'trim', explode( ',', $dm_ipaddress ) );
|
||||
foreach ( $ips as $index => $ip ) :
|
||||
?>
|
||||
<tr>
|
||||
<td><code>A</code></td>
|
||||
<td><code>@</code> <?php esc_html_e( '(or empty)', 'wp-domain-mapping' ); ?></td>
|
||||
<td><code><?php echo esc_html( $ip ); ?></code></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( empty( $dm_ipaddress ) && empty( $dm_cname ) ) : ?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<?php esc_html_e( 'Please configure either a Server IP Address or CNAME to provide DNS setup instructions.', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h3><?php esc_html_e( 'Additional DNS Tips', 'wp-domain-mapping' ); ?></h3>
|
||||
<ul class="dns-tips">
|
||||
<li>
|
||||
<?php esc_html_e( 'Most DNS changes take 24-48 hours to fully propagate worldwide.', 'wp-domain-mapping' ); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php esc_html_e( 'For "www" subdomain, create a separate CNAME record with "www" as the name pointing to the same value.', 'wp-domain-mapping' ); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php esc_html_e( 'If you\'re using Cloudflare or similar services, you may need to adjust proxy settings.', 'wp-domain-mapping' ); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php esc_html_e( 'For SSL to work properly, make sure your web server is configured with the appropriate SSL certificates for mapped domains.', 'wp-domain-mapping' ); ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php esc_html_e( 'Installation Check', 'wp-domain-mapping' ); ?></h2>
|
||||
<table class="widefat striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Status', 'wp-domain-mapping' ); ?></th>
|
||||
<th><?php esc_html_e( 'Check', 'wp-domain-mapping' ); ?></th>
|
||||
<th><?php esc_html_e( 'Value', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( file_exists( WP_CONTENT_DIR . '/sunrise.php' ) ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'sunrise.php file', 'wp-domain-mapping' ); ?></td>
|
||||
<td>
|
||||
<?php if ( file_exists( WP_CONTENT_DIR . '/sunrise.php' ) ) : ?>
|
||||
<?php esc_html_e( 'Found', 'wp-domain-mapping' ); ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: WordPress content directory */
|
||||
esc_html__( 'Not found - copy sunrise.php to %s', 'wp-domain-mapping' ),
|
||||
'<code>' . esc_html( WP_CONTENT_DIR ) . '</code>'
|
||||
);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( defined( 'SUNRISE' ) ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'SUNRISE constant', 'wp-domain-mapping' ); ?></td>
|
||||
<td>
|
||||
<?php if ( defined( 'SUNRISE' ) ) : ?>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: SUNRISE constant value */
|
||||
esc_html__( 'Defined as: %s', 'wp-domain-mapping' ),
|
||||
'<code>' . esc_html( SUNRISE ) . '</code>'
|
||||
);
|
||||
?>
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( 'Not defined - add to wp-config.php: ', 'wp-domain-mapping' ); ?>
|
||||
<code>define( 'SUNRISE', 'on' );</code>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( defined( 'SUNRISE_LOADED' ) ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'SUNRISE_LOADED', 'wp-domain-mapping' ); ?></td>
|
||||
<td>
|
||||
<?php if ( defined( 'SUNRISE_LOADED' ) ) : ?>
|
||||
<?php esc_html_e( 'Loaded successfully', 'wp-domain-mapping' ); ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
if ( defined( 'SUNRISE' ) ) {
|
||||
esc_html_e( 'Not loaded - make sure SUNRISE is defined before the require_once() in wp-config.php', 'wp-domain-mapping' );
|
||||
} else {
|
||||
esc_html_e( 'Not loaded - SUNRISE constant not defined', 'wp-domain-mapping' );
|
||||
}
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( ! defined( 'COOKIE_DOMAIN' ) ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'COOKIE_DOMAIN', 'wp-domain-mapping' ); ?></td>
|
||||
<td>
|
||||
<?php if ( ! defined( 'COOKIE_DOMAIN' ) ) : ?>
|
||||
<?php esc_html_e( 'Not defined (correct)', 'wp-domain-mapping' ); ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: COOKIE_DOMAIN constant value */
|
||||
esc_html__( 'Defined as: %s - remove this from wp-config.php', 'wp-domain-mapping' ),
|
||||
'<code>' . esc_html( COOKIE_DOMAIN ) . '</code>'
|
||||
);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
global $wpdb;
|
||||
$tables_exist = true;
|
||||
foreach ( array(
|
||||
$wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS,
|
||||
$wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_LOGINS,
|
||||
$wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_LOGS,
|
||||
) as $table ) {
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) != $table ) {
|
||||
$tables_exist = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if ( $tables_exist ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'Database tables', 'wp-domain-mapping' ); ?></td>
|
||||
<td>
|
||||
<?php if ( $tables_exist ) : ?>
|
||||
<?php esc_html_e( 'All tables exist', 'wp-domain-mapping' ); ?>
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( 'Some tables are missing - deactivate and reactivate the plugin', 'wp-domain-mapping' ); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( is_multisite() ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'Multisite', 'wp-domain-mapping' ); ?></td>
|
||||
<td>
|
||||
<?php if ( is_multisite() ) : ?>
|
||||
<?php esc_html_e( 'Enabled', 'wp-domain-mapping' ); ?>
|
||||
<?php else : ?>
|
||||
<?php esc_html_e( 'Not enabled - this plugin requires WordPress Multisite', 'wp-domain-mapping' ); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Main cards */
|
||||
.domain-mapping-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ccd0d4;
|
||||
border-radius: 4px;
|
||||
max-width: unset;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
/* Form elements */
|
||||
.form-table th {
|
||||
width: 200px;
|
||||
padding: 15px 10px 15px 0;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
/* Description text */
|
||||
.description {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* DNS instructions */
|
||||
.dns-instructions {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dns-example {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 3px;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.dns-example h4 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.dns-tips {
|
||||
list-style: disc;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.dns-tips li {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Status indicators */
|
||||
.dashicons-yes-alt,
|
||||
.dashicons-no-alt {
|
||||
font-size: 24px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
/* Notices */
|
||||
.notice {
|
||||
padding: 8px 12px;
|
||||
border-radius: 3px;
|
||||
margin: 5px 0 15px;
|
||||
}
|
||||
|
||||
.notice p {
|
||||
margin: 0.5em 0;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media screen and (max-width: 782px) {
|
||||
.form-table th {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
display: block;
|
||||
padding: 0 0 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
964
admin/templates.php
Normal file
964
admin/templates.php
Normal file
|
@ -0,0 +1,964 @@
|
|||
<?php
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render admin settings page (continued)
|
||||
*/
|
||||
function dm_render_settings_page_continued($dm_301_redirect, $dm_redirect_admin, $dm_user_settings, $dm_no_primary_domain, $dm_ipaddress, $dm_cname, $core) {
|
||||
?>
|
||||
<legend class="screen-reader-text"><?php _e('Permanent Redirect', 'wp-domain-mapping'); ?></legend>
|
||||
<label for="permanent_redirect">
|
||||
<input type="checkbox" name="permanent_redirect" id="permanent_redirect" value="1" <?php checked($dm_301_redirect, 1); ?> />
|
||||
<?php _e('Use Permanent Redirect (301)', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php _e('Use 301 redirects instead of 302 redirects. This is better for SEO but may cause caching issues.', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php _e('User Settings', 'wp-domain-mapping'); ?></legend>
|
||||
<label for="dm_user_settings">
|
||||
<input type="checkbox" name="dm_user_settings" id="dm_user_settings" value="1" <?php checked($dm_user_settings, 1); ?> />
|
||||
<?php _e('Enable User Domain Mapping Page', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php _e('Allow site administrators to manage their domain mappings from the Tools menu.', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php _e('Redirect Admin', 'wp-domain-mapping'); ?></legend>
|
||||
<label for="always_redirect_admin">
|
||||
<input type="checkbox" name="always_redirect_admin" id="always_redirect_admin" value="1" <?php checked($dm_redirect_admin, 1); ?> />
|
||||
<?php _e('Redirect Admin Pages to Original Domain', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php _e('Force admin pages to use the original WordPress domain instead of the mapped domain.', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php _e('Disable Primary Domain', 'wp-domain-mapping'); ?></legend>
|
||||
<label for="dm_no_primary_domain">
|
||||
<input type="checkbox" name="dm_no_primary_domain" id="dm_no_primary_domain" value="1" <?php checked($dm_no_primary_domain, 1); ?> />
|
||||
<?php _e('Disable Primary Domain Check', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php _e('Do not redirect to the primary domain, but allow access through any mapped domain.', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="submit">
|
||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e('Save Configuration', 'wp-domain-mapping'); ?>" />
|
||||
<a href="<?php echo esc_url(admin_url('network/sites.php?page=domains')); ?>" class="button button-secondary">
|
||||
<?php _e('Manage Domains', 'wp-domain-mapping'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('DNS Setup Instructions', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<div class="dns-instructions">
|
||||
<?php if (!empty($dm_cname)) : ?>
|
||||
<h3><?php _e('CNAME Method (Recommended)', 'wp-domain-mapping'); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
__('Tell your users to add a DNS "CNAME" record for their domain pointing to: %s', 'wp-domain-mapping'),
|
||||
'<code>' . esc_html($dm_cname) . '</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<div class="dns-example">
|
||||
<h4><?php _e('Example DNS Record', 'wp-domain-mapping'); ?></h4>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Type', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Name', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Value', 'wp-domain-mapping'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>CNAME</code></td>
|
||||
<td><code>@</code> <?php _e('(or empty)', 'wp-domain-mapping'); ?></td>
|
||||
<td><code><?php echo esc_html($dm_cname); ?></code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($dm_ipaddress)) : ?>
|
||||
<h3><?php _e('A Record Method', 'wp-domain-mapping'); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
__('Tell your users to add a DNS "A" record for their domain pointing to: %s', 'wp-domain-mapping'),
|
||||
'<code>' . esc_html($dm_ipaddress) . '</code>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<div class="dns-example">
|
||||
<h4><?php _e('Example DNS Record', 'wp-domain-mapping'); ?></h4>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Type', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Name', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Value', 'wp-domain-mapping'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$ips = array_map('trim', explode(',', $dm_ipaddress));
|
||||
foreach ($ips as $index => $ip) :
|
||||
?>
|
||||
<tr>
|
||||
<td><code>A</code></td>
|
||||
<td><code>@</code> <?php _e('(or empty)', 'wp-domain-mapping'); ?></td>
|
||||
<td><code><?php echo esc_html($ip); ?></code></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($dm_ipaddress) && empty($dm_cname)) : ?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<?php _e('Please configure either a Server IP Address or CNAME to provide DNS setup instructions.', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h3><?php _e('Additional DNS Tips', 'wp-domain-mapping'); ?></h3>
|
||||
<ul class="dns-tips">
|
||||
<li>
|
||||
<?php _e('Most DNS changes take 24-48 hours to fully propagate worldwide.', 'wp-domain-mapping'); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php _e('For "www" subdomain, create a separate CNAME record with "www" as the name pointing to the same value.', 'wp-domain-mapping'); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php _e('If you\'re using Cloudflare or similar services, you may need to adjust proxy settings.', 'wp-domain-mapping'); ?>
|
||||
</li>
|
||||
<li>
|
||||
<?php _e('For SSL to work properly, make sure your web server is configured with the appropriate SSL certificates for mapped domains.', 'wp-domain-mapping'); ?>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Installation Check', 'wp-domain-mapping'); ?></h2>
|
||||
<table class="widefat striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?php _e('Status', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Check', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Value', 'wp-domain-mapping'); ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (file_exists(WP_CONTENT_DIR . '/sunrise.php')) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php _e('sunrise.php file', 'wp-domain-mapping'); ?></td>
|
||||
<td>
|
||||
<?php if (file_exists(WP_CONTENT_DIR . '/sunrise.php')) : ?>
|
||||
<?php _e('Found', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
printf(
|
||||
__('Not found - copy sunrise.php to %s', 'wp-domain-mapping'),
|
||||
'<code>' . esc_html(WP_CONTENT_DIR) . '</code>'
|
||||
);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (defined('SUNRISE')) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php _e('SUNRISE constant', 'wp-domain-mapping'); ?></td>
|
||||
<td>
|
||||
<?php if (defined('SUNRISE')) : ?>
|
||||
<?php
|
||||
printf(
|
||||
__('Defined as: %s', 'wp-domain-mapping'),
|
||||
'<code>' . esc_html(SUNRISE) . '</code>'
|
||||
);
|
||||
?>
|
||||
<?php else : ?>
|
||||
<?php _e('Not defined - add to wp-config.php: ', 'wp-domain-mapping'); ?>
|
||||
<code>define( 'SUNRISE', 'on' );</code>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (defined('SUNRISE_LOADED')) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php _e('SUNRISE_LOADED', 'wp-domain-mapping'); ?></td>
|
||||
<td>
|
||||
<?php if (defined('SUNRISE_LOADED')) : ?>
|
||||
<?php _e('Loaded successfully', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
if (defined('SUNRISE')) {
|
||||
_e('Not loaded - make sure SUNRISE is defined before the require_once() in wp-config.php', 'wp-domain-mapping');
|
||||
} else {
|
||||
_e('Not loaded - SUNRISE constant not defined', 'wp-domain-mapping');
|
||||
}
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (!defined('COOKIE_DOMAIN')) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php _e('COOKIE_DOMAIN', 'wp-domain-mapping'); ?></td>
|
||||
<td>
|
||||
<?php if (!defined('COOKIE_DOMAIN')) : ?>
|
||||
<?php _e('Not defined (correct)', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
printf(
|
||||
__('Defined as: %s - remove this from wp-config.php', 'wp-domain-mapping'),
|
||||
'<code>' . esc_html(COOKIE_DOMAIN) . '</code>'
|
||||
);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
global $wpdb;
|
||||
$tables_exist = true;
|
||||
foreach (array(
|
||||
$wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS,
|
||||
$wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_LOGINS,
|
||||
$wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_LOGS,
|
||||
) as $table) {
|
||||
if ($wpdb->get_var("SHOW TABLES LIKE '$table'") != $table) {
|
||||
$tables_exist = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if ($tables_exist) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php _e('Database tables', 'wp-domain-mapping'); ?></td>
|
||||
<td>
|
||||
<?php if ($tables_exist) : ?>
|
||||
<?php _e('All tables exist', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<?php _e('Some tables are missing - deactivate and reactivate the plugin', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (is_multisite()) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php _e('Multisite', 'wp-domain-mapping'); ?></td>
|
||||
<td>
|
||||
<?php if (is_multisite()) : ?>
|
||||
<?php _e('Enabled', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<?php _e('Not enabled - this plugin requires WordPress Multisite', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the settings page by calling both parts
|
||||
*/
|
||||
function dm_render_settings_page() {
|
||||
// Get current options
|
||||
$dm_ipaddress = get_site_option('dm_ipaddress', '');
|
||||
$dm_cname = get_site_option('dm_cname', '');
|
||||
$dm_remote_login = get_site_option('dm_remote_login', 1);
|
||||
$dm_301_redirect = get_site_option('dm_301_redirect', 0);
|
||||
$dm_redirect_admin = get_site_option('dm_redirect_admin', 1);
|
||||
$dm_user_settings = get_site_option('dm_user_settings', 1);
|
||||
$dm_no_primary_domain = get_site_option('dm_no_primary_domain', 0);
|
||||
|
||||
// Get core instance
|
||||
$core = WP_Domain_Mapping_Core::get_instance();
|
||||
|
||||
// Call the first part of the function
|
||||
dm_render_settings_page_continued($dm_301_redirect, $dm_redirect_admin, $dm_user_settings, $dm_no_primary_domain, $dm_ipaddress, $dm_cname, $core);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render user domain mapping page
|
||||
*/
|
||||
function dm_render_user_page() {
|
||||
global $wpdb;
|
||||
|
||||
$core = WP_Domain_Mapping_Core::get_instance();
|
||||
$db = WP_Domain_Mapping_DB::get_instance();
|
||||
|
||||
$protocol = is_ssl() ? 'https://' : 'http://';
|
||||
$domains = $db->get_domains_by_blog_id($wpdb->blogid);
|
||||
|
||||
// Display updated messages
|
||||
if (isset($_GET['updated'])) {
|
||||
echo '<div class="notice notice-success"><p>';
|
||||
switch ($_GET['updated']) {
|
||||
case 'add':
|
||||
_e('Domain added successfully.', 'wp-domain-mapping');
|
||||
break;
|
||||
case 'exists':
|
||||
_e('This domain is already mapped to a site.', 'wp-domain-mapping');
|
||||
break;
|
||||
case 'primary':
|
||||
_e('Primary domain updated.', 'wp-domain-mapping');
|
||||
break;
|
||||
case 'del':
|
||||
_e('Domain deleted successfully.', 'wp-domain-mapping');
|
||||
break;
|
||||
}
|
||||
echo '</p></div>';
|
||||
}
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Domain Mapping', 'wp-domain-mapping'); ?></h1>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Add New Domain', 'wp-domain-mapping'); ?></h2>
|
||||
<form method="post" action="<?php echo esc_url(admin_url('tools.php?page=domainmapping')); ?>">
|
||||
<?php wp_nonce_field('domain_mapping'); ?>
|
||||
<input type="hidden" name="action" value="add" />
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><label for="domain"><?php _e('Domain', 'wp-domain-mapping'); ?></label></th>
|
||||
<td>
|
||||
<input name="domain" id="domain" type="text" value="" class="regular-text"
|
||||
placeholder="example.com" pattern="^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$" required />
|
||||
<p class="description">
|
||||
<?php _e('Enter the domain without http:// or https:// (e.g., example.com)', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e('Primary Domain', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php _e('Primary Domain', 'wp-domain-mapping'); ?></legend>
|
||||
<label for="primary">
|
||||
<input name="primary" type="checkbox" id="primary" value="1" />
|
||||
<?php _e('Set this domain as the primary domain for this site', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="submit">
|
||||
<input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e('Add Domain', 'wp-domain-mapping'); ?>" />
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($domains)): ?>
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Your Mapped Domains', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped domains-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Domain', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Primary', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Actions', 'wp-domain-mapping'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($domains as $domain): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($protocol . $domain->domain); ?>" target="_blank">
|
||||
<?php echo esc_html($domain->domain); ?>
|
||||
<span class="dashicons dashicons-external" style="font-size: 14px; line-height: 1.3; opacity: 0.7;"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($domain->active == 1): ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<span class="screen-reader-text"><?php _e('Yes', 'wp-domain-mapping'); ?></span>
|
||||
<?php else: ?>
|
||||
<a href="<?php echo wp_nonce_url(add_query_arg(
|
||||
array('page' => 'domainmapping', 'action' => 'primary', 'domain' => $domain->domain),
|
||||
admin_url('tools.php')
|
||||
), 'domain_mapping'); ?>" class="button button-small">
|
||||
<?php _e('Make Primary', 'wp-domain-mapping'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($domain->active != 1): ?>
|
||||
<a href="<?php echo wp_nonce_url(add_query_arg(
|
||||
array('page' => 'domainmapping', 'action' => 'delete', 'domain' => $domain->domain),
|
||||
admin_url('tools.php')
|
||||
), 'delete' . $domain->domain); ?>" class="button button-small button-link-delete" onclick="return confirm('<?php _e('Are you sure you want to delete this domain?', 'wp-domain-mapping'); ?>');">
|
||||
<?php _e('Delete', 'wp-domain-mapping'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('DNS Configuration Instructions', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<?php
|
||||
$ipaddress = get_site_option('dm_ipaddress');
|
||||
$cname = get_site_option('dm_cname');
|
||||
|
||||
if (!$ipaddress && !$cname): ?>
|
||||
<div class="notice notice-error">
|
||||
<p><?php _e('The site administrator has not configured the DNS settings. Please contact them for assistance.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p><?php _e('To map your domain to this site, you need to update your DNS records with your domain registrar.', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<?php if ($cname): ?>
|
||||
<h3><?php _e('CNAME Method (Recommended)', 'wp-domain-mapping'); ?></h3>
|
||||
<p><?php printf(__('Create a CNAME record for your domain pointing to: <code>%s</code>', 'wp-domain-mapping'), esc_html($cname)); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($ipaddress): ?>
|
||||
<h3><?php _e('A Record Method', 'wp-domain-mapping'); ?></h3>
|
||||
<p><?php printf(__('Create an A record for your domain pointing to: <code>%s</code>', 'wp-domain-mapping'), esc_html($ipaddress)); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="description"><?php _e('DNS changes may take 24-48 hours to fully propagate across the internet.', 'wp-domain-mapping'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render health page
|
||||
*/
|
||||
function dm_render_health_page() {
|
||||
// Check permissions
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to access this page.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Get all domains
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
$domains = $wpdb->get_results("
|
||||
SELECT d.*, b.domain as original_domain, b.path
|
||||
FROM {$table} d
|
||||
JOIN {$wpdb->blogs} b ON d.blog_id = b.blog_id
|
||||
ORDER BY d.blog_id ASC, d.active DESC
|
||||
");
|
||||
|
||||
// Get health check results
|
||||
$health_results = get_site_option('dm_domain_health_results', array());
|
||||
|
||||
// Display page
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
|
||||
<?php
|
||||
// Display success messages
|
||||
if (isset($_GET['checked']) && $_GET['checked']) {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__('Domain health check completed.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
}
|
||||
|
||||
if (isset($_GET['settings-updated']) && $_GET['settings-updated']) {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__('Settings saved.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Domain Health Status', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<?php if ($health_data) : ?>
|
||||
<button type="button" class="button button-small show-health-details" data-domain="<?php echo esc_attr($domain->domain); ?>">
|
||||
<?php _e('Details', 'wp-domain-mapping'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ($health_data) : ?>
|
||||
<tr class="health-details-row" id="health-details-<?php echo esc_attr($domain_key); ?>" style="display: none;">
|
||||
<td colspan="7">
|
||||
<div class="health-details-content">
|
||||
<h4><?php echo sprintf(__('Health Details for %s', 'wp-domain-mapping'), esc_html($domain->domain)); ?></h4>
|
||||
|
||||
<table class="widefat striped" style="margin-top: 10px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?php _e('Last Check', 'wp-domain-mapping'); ?></th>
|
||||
<td><?php echo isset($health_data['last_check']) ? esc_html(date('Y-m-d H:i:s', strtotime($health_data['last_check']))) : '-'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('DNS Status', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<?php if (isset($health_data['dns_status'])) : ?>
|
||||
<?php if ($health_data['dns_status'] === 'success') : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php _e('DNS correctly configured', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-warning" style="color: #dc3232;"></span>
|
||||
<?php echo esc_html($health_data['dns_message']); ?>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<?php _e('Not checked', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('Resolved IP', 'wp-domain-mapping'); ?></th>
|
||||
<td><?php echo isset($health_data['resolved_ip']) ? esc_html($health_data['resolved_ip']) : '-'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('SSL Valid', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<?php if (isset($health_data['ssl_valid'])) : ?>
|
||||
<?php if ($health_data['ssl_valid']) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php _e('Valid', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-warning" style="color: #dc3232;"></span>
|
||||
<?php _e('Invalid', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<?php _e('Not checked', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('SSL Expiry', 'wp-domain-mapping'); ?></th>
|
||||
<td><?php echo isset($health_data['ssl_expiry']) ? esc_html(date('Y-m-d', strtotime($health_data['ssl_expiry']))) : '-'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('Response Code', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
if (isset($health_data['response_code'])) {
|
||||
echo esc_html($health_data['response_code']);
|
||||
if ($health_data['response_code'] >= 200 && $health_data['response_code'] < 400) {
|
||||
echo ' <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>';
|
||||
} else {
|
||||
echo ' <span class="dashicons dashicons-warning" style="color: #dc3232;"></span>';
|
||||
}
|
||||
} else {
|
||||
echo '-';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="7"><?php _e('No domains found.', 'wp-domain-mapping'); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Health Check Settings', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render import/export page
|
||||
*/
|
||||
function dm_render_import_export_page() {
|
||||
// Check permissions
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to access this page.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Output success messages
|
||||
if (isset($_GET['imported']) && $_GET['imported']) {
|
||||
$count = intval($_GET['imported']);
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
sprintf(
|
||||
_n(
|
||||
'%d domain mapping imported successfully.',
|
||||
'%d domain mappings imported successfully.',
|
||||
$count,
|
||||
'wp-domain-mapping'
|
||||
),
|
||||
$count
|
||||
) .
|
||||
'</p></div>';
|
||||
}
|
||||
|
||||
if (isset($_GET['export']) && $_GET['export'] == 'success') {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__('Domain mappings exported successfully.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
}
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Export Domain Mappings', 'wp-domain-mapping'); ?></h2>
|
||||
<p><?php _e('Export all domain mappings to a CSV file.', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('domain_mapping_export', 'domain_mapping_export_nonce'); ?>
|
||||
<input type="hidden" name="domain_mapping_export" value="1">
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="include_header" value="1" checked>
|
||||
<?php _e('Include column headers', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="blog_id_filter"><?php _e('Export for specific site ID (optional):', 'wp-domain-mapping'); ?></label>
|
||||
<input type="number" id="blog_id_filter" name="blog_id_filter" min="1" class="regular-text">
|
||||
<p class="description"><?php _e('Leave empty to export all domains.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e('Export to CSV', 'wp-domain-mapping'); ?>">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Import Domain Mappings', 'wp-domain-mapping'); ?></h2>
|
||||
<p><?php _e('Import domain mappings from a CSV file.', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<form method="post" enctype="multipart/form-data" id="domain-mapping-import-form">
|
||||
<?php wp_nonce_field('domain_mapping_import', 'domain_mapping_import_nonce'); ?>
|
||||
<input type="hidden" name="domain_mapping_import" value="1">
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="csv_file"><?php _e('CSV File:', 'wp-domain-mapping'); ?></label><br>
|
||||
<input type="file" id="csv_file" name="csv_file" accept=".csv" required>
|
||||
<p class="description">
|
||||
<?php _e('The CSV file should have the columns: blog_id, domain, active (1 or 0).', 'wp-domain-mapping'); ?><br>
|
||||
<?php _e('Example: 1,example.com,1', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="has_header" value="1" checked>
|
||||
<?php _e('First row contains column headers', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="update_existing" value="1" checked>
|
||||
<?php _e('Update existing mappings', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description"><?php _e('If unchecked, will skip domains that already exist.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="validate_sites" value="1" checked>
|
||||
<?php _e('Validate site IDs', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description"><?php _e('If checked, will only import domains for existing sites.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e('Import from CSV', 'wp-domain-mapping'); ?>">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<div id="import-progress" style="display: none; margin-top: 20px;">
|
||||
<p><?php _e('Processing import...', 'wp-domain-mapping'); ?></p>
|
||||
<div class="progress-bar-outer" style="background-color: #f0f0f1; border-radius: 4px; height: 20px; width: 100%; overflow: hidden;">
|
||||
<div class="progress-bar-inner" style="background-color: #2271b1; height: 100%; width: 0%;"></div>
|
||||
</div>
|
||||
<p class="progress-text">0%</p>
|
||||
</div>
|
||||
|
||||
<div id="import-results" style="display: none; margin-top: 20px;">
|
||||
<h3><?php _e('Import Results', 'wp-domain-mapping'); ?></h3>
|
||||
<div class="import-summary"></div>
|
||||
<div class="import-details"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('CSV Format', 'wp-domain-mapping'); ?></h2>
|
||||
<p><?php _e('The CSV file should follow this format:', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<table class="widefat" style="margin-top: 10px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>blog_id</th>
|
||||
<th>domain</th>
|
||||
<th>active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>example.com</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>example.org</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ul style="margin-top: 15px;">
|
||||
<li><strong>blog_id</strong>: <?php _e('The ID of the WordPress site (required)', 'wp-domain-mapping'); ?></li>
|
||||
<li><strong>domain</strong>: <?php _e('The domain name without http:// or https:// (required)', 'wp-domain-mapping'); ?></li>
|
||||
<li><strong>active</strong>: <?php _e('Set to 1 to make this the primary domain, 0 otherwise (required)', 'wp-domain-mapping'); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
183
admin/user-page.php
Normal file
183
admin/user-page.php
Normal file
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
/**
|
||||
* User domain mapping management page
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$protocol = isset($protocol) ? $protocol : (is_ssl() ? 'https://' : 'http://');
|
||||
$domains = isset($domains) ? $domains : array();
|
||||
|
||||
// Initialize logs array if not set to prevent PHP warnings
|
||||
if (!isset($logs) || !is_array($logs)) {
|
||||
$logs = array();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Domain Mapping', 'wp-domain-mapping'); ?></h1>
|
||||
|
||||
<?php if (isset($_GET['updated'])): ?>
|
||||
<div class="notice notice-success">
|
||||
<p>
|
||||
<?php
|
||||
switch ($_GET['updated']) {
|
||||
case 'add':
|
||||
_e('Domain added successfully.', 'wp-domain-mapping');
|
||||
break;
|
||||
case 'exists':
|
||||
_e('This domain is already mapped to a site.', 'wp-domain-mapping');
|
||||
break;
|
||||
case 'primary':
|
||||
_e('Primary domain updated.', 'wp-domain-mapping');
|
||||
break;
|
||||
case 'del':
|
||||
_e('Domain deleted successfully.', 'wp-domain-mapping');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Add New Domain', 'wp-domain-mapping'); ?></h2>
|
||||
<form method="post" action="<?php echo esc_url(admin_url('tools.php?page=domainmapping')); ?>">
|
||||
<?php wp_nonce_field('domain_mapping'); ?>
|
||||
<input type="hidden" name="action" value="add" />
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><label for="domain"><?php _e('Domain', 'wp-domain-mapping'); ?></label></th>
|
||||
<td>
|
||||
<input name="domain" id="domain" type="text" value="" class="regular-text"
|
||||
placeholder="example.com" pattern="^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$" required />
|
||||
<p class="description">
|
||||
<?php _e('Enter the domain without http:// or https:// (e.g., example.com)', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php _e('Primary Domain', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><?php _e('Primary Domain', 'wp-domain-mapping'); ?></legend>
|
||||
<label for="primary">
|
||||
<input name="primary" type="checkbox" id="primary" value="1" />
|
||||
<?php _e('Set this domain as the primary domain for this site', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="submit">
|
||||
<input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e('Add Domain', 'wp-domain-mapping'); ?>" />
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($domains)): ?>
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('Your Mapped Domains', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped domains-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Domain', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Primary', 'wp-domain-mapping'); ?></th>
|
||||
<th><?php _e('Actions', 'wp-domain-mapping'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($domains as $domain): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($protocol . $domain['domain']); ?>" target="_blank">
|
||||
<?php echo esc_html($domain['domain']); ?>
|
||||
<span class="dashicons dashicons-external" style="font-size: 14px; line-height: 1.3; opacity: 0.7;"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($domain['active'] == 1): ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<span class="screen-reader-text"><?php _e('Yes', 'wp-domain-mapping'); ?></span>
|
||||
<?php else: ?>
|
||||
<a href="<?php echo wp_nonce_url(add_query_arg(
|
||||
array('page' => 'domainmapping', 'action' => 'primary', 'domain' => $domain['domain']),
|
||||
admin_url('tools.php')
|
||||
), 'domain_mapping'); ?>" class="button button-small">
|
||||
<?php _e('Make Primary', 'wp-domain-mapping'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($domain['active'] != 1): ?>
|
||||
<a href="<?php echo wp_nonce_url(add_query_arg(
|
||||
array('page' => 'domainmapping', 'action' => 'delete', 'domain' => $domain['domain']),
|
||||
admin_url('tools.php')
|
||||
), 'delete' . $domain['domain']); ?>" class="button button-small button-link-delete" onclick="return confirm('<?php _e('Are you sure you want to delete this domain?', 'wp-domain-mapping'); ?>');">
|
||||
<?php _e('Delete', 'wp-domain-mapping'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e('DNS Configuration Instructions', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<?php
|
||||
$ipaddress = get_site_option('dm_ipaddress');
|
||||
$cname = get_site_option('dm_cname');
|
||||
|
||||
if (!$ipaddress && !$cname): ?>
|
||||
<div class="notice notice-error">
|
||||
<p><?php _e('The site administrator has not configured the DNS settings. Please contact them for assistance.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p><?php _e('To map your domain to this site, you need to update your DNS records with your domain registrar.', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<?php if ($cname): ?>
|
||||
<h3><?php _e('CNAME Method (Recommended)', 'wp-domain-mapping'); ?></h3>
|
||||
<p><?php printf(__('Create a CNAME record for your domain pointing to: <code>%s</code>', 'wp-domain-mapping'), esc_html($cname)); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($ipaddress): ?>
|
||||
<h3><?php _e('A Record Method', 'wp-domain-mapping'); ?></h3>
|
||||
<p><?php printf(__('Create an A record for your domain pointing to: <code>%s</code>', 'wp-domain-mapping'), esc_html($ipaddress)); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="description"><?php _e('DNS changes may take 24-48 hours to fully propagate across the internet.', 'wp-domain-mapping'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Main cards */
|
||||
.domain-mapping-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ccd0d4;
|
||||
border-radius: 4px;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.domains-table .column-primary {
|
||||
width: 150px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.domains-table .column-actions {
|
||||
width: 120px;
|
||||
}
|
||||
</style>
|
64
assets/css/admin.css
Normal file
64
assets/css/admin.css
Normal file
|
@ -0,0 +1,64 @@
|
|||
.card {
|
||||
background: #fff;
|
||||
border: 1px solid #ccd0d4;
|
||||
border-radius: 4px;
|
||||
max-width: unset;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
.styles-sync-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
border-bottom: 1px solid #c3c4c7;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.styles-tab {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.styles-tab.active {
|
||||
border-bottom: 2px solid #007cba;
|
||||
font-weight: 600;
|
||||
background: #f0f0f1;
|
||||
}
|
||||
.styles-tab:hover:not(.active) {
|
||||
background: #f0f0f1;
|
||||
border-bottom-color: #dcdcde;
|
||||
}
|
||||
.styles-sync-content { flex: 1; }
|
||||
.tablenav { margin: 10px 0; }
|
||||
.tablenav-pages { float: right; }
|
||||
.tablenav-pages a, .tablenav-pages span { padding: 5px 10px; }
|
||||
.form-table th { width: 200px; }
|
||||
.form-table td { padding: 10px
|
||||
|
||||
System: 0; }
|
||||
.description { color: #666; font-size: 12px; }
|
||||
.notice { padding: 8px 12px; border-radius: 3px; }
|
||||
.notice-success { background-color: #dff0d8; border-left: 4px solid #46b450; }
|
||||
.notice-error { background-color: #f2dede; border-left: 4px solid #dc3232; }
|
||||
|
||||
/* Responsive Styles */
|
||||
@media screen and (max-width: 782px) {
|
||||
.form-table th {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
.form-table td {
|
||||
display: block;
|
||||
padding: 5px 0 15px;
|
||||
}
|
||||
.wp-list-table th.column-primary ~ th,
|
||||
.wp-list-table td.column-primary ~ td {
|
||||
display: none;
|
||||
}
|
||||
.wp-list-table th.column-primary,
|
||||
.wp-list-table td.column-primary {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
134
assets/js/admin.js
Normal file
134
assets/js/admin.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* WP Domain Mapping admin JavaScript
|
||||
*/
|
||||
jQuery(document).ready(function($) {
|
||||
// Tab switching
|
||||
$('.styles-tab').on('click', function() {
|
||||
$('.styles-tab').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
var tab = $(this).data('tab');
|
||||
$('.styles-section').hide();
|
||||
$('.styles-section[data-section="' + tab + '"]').show();
|
||||
});
|
||||
|
||||
// Domain form validation
|
||||
$('#edit-domain-form').on('submit', function(e) {
|
||||
var domain = $('#domain').val();
|
||||
var blogId = $('#blog_id').val();
|
||||
|
||||
if (!domain) {
|
||||
e.preventDefault();
|
||||
alert(wpDomainMapping.messages.domainRequired);
|
||||
$('#domain').focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!blogId) {
|
||||
e.preventDefault();
|
||||
alert(wpDomainMapping.messages.siteRequired);
|
||||
$('#blog_id').focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Check all domains
|
||||
$('#select-all').on('change', function() {
|
||||
$('.domain-checkbox').prop('checked', this.checked);
|
||||
});
|
||||
|
||||
// AJAX domain operations
|
||||
function showNotice(selector, message, type) {
|
||||
$(selector).removeClass('notice-success notice-error')
|
||||
.addClass('notice-' + type)
|
||||
.html('<p>' + message + '</p>')
|
||||
.show()
|
||||
.delay(3000)
|
||||
.fadeOut();
|
||||
}
|
||||
|
||||
// Save domain
|
||||
$('#edit-domain-form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var formData = $(this).serializeArray();
|
||||
formData.push({name: 'action', value: 'dm_handle_actions'});
|
||||
formData.push({name: 'action_type', value: 'save'});
|
||||
formData.push({name: 'nonce', value: wpDomainMapping.nonce});
|
||||
|
||||
$('#edit-domain-status').text(wpDomainMapping.messages.saving).show();
|
||||
|
||||
$.ajax({
|
||||
url: wpDomainMapping.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showNotice('#edit-domain-status', response.data, 'success');
|
||||
setTimeout(function() { location.reload(); }, 1000);
|
||||
} else {
|
||||
showNotice('#edit-domain-status', response.data || wpDomainMapping.messages.error, 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showNotice('#edit-domain-status', wpDomainMapping.messages.error, 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Bulk actions
|
||||
$('#domain-list-form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var selectedDomains = [];
|
||||
$('.domain-checkbox:checked').each(function() {
|
||||
selectedDomains.push($(this).val());
|
||||
});
|
||||
|
||||
if (selectedDomains.length === 0) {
|
||||
showNotice('#domain-status', wpDomainMapping.messages.noSelection, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
var action = $('#bulk-action-selector-top').val();
|
||||
if (action === '-1') return;
|
||||
|
||||
if (confirm('Are you sure you want to delete the selected domains?')) {
|
||||
$('#domain-status').text(wpDomainMapping.messages.processing).show();
|
||||
|
||||
$.ajax({
|
||||
url: wpDomainMapping.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'dm_handle_actions',
|
||||
action_type: 'delete',
|
||||
domains: selectedDomains,
|
||||
nonce: wpDomainMapping.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showNotice('#domain-status', response.data, 'success');
|
||||
setTimeout(function() { location.reload(); }, 1000);
|
||||
} else {
|
||||
showNotice('#domain-status', response.data || wpDomainMapping.messages.error, 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showNotice('#domain-status', wpDomainMapping.messages.error, 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Copy to clipboard functionality
|
||||
$('.copy-to-clipboard').on('click', function() {
|
||||
var text = $(this).data('text');
|
||||
var tempInput = $('<input>');
|
||||
$('body').append(tempInput);
|
||||
tempInput.val(text).select();
|
||||
document.execCommand('copy');
|
||||
tempInput.remove();
|
||||
|
||||
var $btn = $(this);
|
||||
var originalText = $btn.text();
|
||||
$btn.text('Copied!');
|
||||
setTimeout(function() { $btn.text(originalText); }, 2000);
|
||||
});
|
||||
});
|
389
includes/admin-ui.php
Normal file
389
includes/admin-ui.php
Normal file
|
@ -0,0 +1,389 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin UI functions for WP Domain Mapping plugin
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render domain edit form
|
||||
*
|
||||
* @param object|false $row Domain data if editing, false if adding new
|
||||
*/
|
||||
function dm_edit_domain( $row = false ) {
|
||||
$is_edit = is_object( $row );
|
||||
|
||||
if ( ! $row ) {
|
||||
$row = new stdClass();
|
||||
$row->blog_id = '';
|
||||
$row->domain = '';
|
||||
$row->active = 1;
|
||||
}
|
||||
?>
|
||||
<form id="edit-domain-form" method="POST">
|
||||
<input type="hidden" name="orig_domain" value="<?php echo esc_attr( $is_edit ? $row->domain : '' ); ?>" />
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><label for="blog_id"><?php esc_html_e( 'Site ID', 'wp-domain-mapping' ); ?></label></th>
|
||||
<td>
|
||||
<input type="number" id="blog_id" name="blog_id" value="<?php echo esc_attr( $row->blog_id ); ?>" class="regular-text" required />
|
||||
<?php if ( ! $is_edit ) : ?>
|
||||
<p class="description">
|
||||
<?php
|
||||
$site_list_url = network_admin_url( 'sites.php' );
|
||||
printf(
|
||||
/* translators: %s: URL to sites list */
|
||||
wp_kses(
|
||||
__( 'Not sure about Site ID? <a href="%s" target="_blank">View all sites</a> to find the ID.', 'wp-domain-mapping' ),
|
||||
array( 'a' => array( 'href' => array(), 'target' => array() ) )
|
||||
),
|
||||
esc_url( $site_list_url )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="domain"><?php esc_html_e( 'Domain', 'wp-domain-mapping' ); ?></label></th>
|
||||
<td>
|
||||
<input type="text" id="domain" name="domain" value="<?php echo esc_attr( $row->domain ); ?>" class="regular-text" required
|
||||
placeholder="example.com" pattern="^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$" />
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Enter the domain without http:// or https:// (e.g., example.com)', 'wp-domain-mapping' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="active"><?php esc_html_e( 'Primary', 'wp-domain-mapping' ); ?></label></th>
|
||||
<td>
|
||||
<input type="checkbox" id="active" name="active" value="1" <?php checked( $row->active, 1 ); ?> />
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Set as the primary domain for this site', 'wp-domain-mapping' ); ?>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ( get_site_option( 'dm_no_primary_domain' ) == 1 ) : ?>
|
||||
<tr>
|
||||
<td colspan="2" class="notice notice-warning">
|
||||
<p><?php esc_html_e( 'Warning! Primary domains are currently disabled in network settings.', 'wp-domain-mapping' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
<p>
|
||||
<input type="submit" class="button button-primary" value="<?php echo $is_edit
|
||||
? esc_attr__( 'Update Domain', 'wp-domain-mapping' )
|
||||
: esc_attr__( 'Add Domain', 'wp-domain-mapping' ); ?>" />
|
||||
|
||||
<?php if ( $is_edit ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'network/sites.php?page=domains' ) ); ?>" class="button button-secondary">
|
||||
<?php esc_html_e( 'Cancel', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render domain listing table
|
||||
*
|
||||
* @param array $rows Domain data rows
|
||||
*/
|
||||
function dm_domain_listing( $rows ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $rows ) {
|
||||
echo '<div class="notice notice-info"><p>' . esc_html__( 'No domains found.', 'wp-domain-mapping' ) . '</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$edit_url = network_admin_url(
|
||||
file_exists( ABSPATH . 'wp-admin/network/site-info.php' )
|
||||
? 'site-info.php'
|
||||
: ( file_exists( ABSPATH . 'wp-admin/ms-sites.php' ) ? 'ms-sites.php' : 'wpmu-blogs.php' )
|
||||
);
|
||||
?>
|
||||
<div class="tablenav top">
|
||||
<div class="alignleft actions bulkactions">
|
||||
<label for="bulk-action-selector-top" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'wp-domain-mapping' ); ?></label>
|
||||
<select id="bulk-action-selector-top" name="action">
|
||||
<option value="-1"><?php esc_html_e( 'Bulk Actions', 'wp-domain-mapping' ); ?></option>
|
||||
<option value="delete"><?php esc_html_e( 'Delete', 'wp-domain-mapping' ); ?></option>
|
||||
</select>
|
||||
<input type="submit" class="button action" value="<?php esc_attr_e( 'Apply', 'wp-domain-mapping' ); ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="wp-list-table widefat striped domains-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="manage-column column-cb check-column">
|
||||
<input id="select-all" type="checkbox" />
|
||||
</td>
|
||||
<th scope="col" class="column-site-id"><?php esc_html_e( 'Site ID', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-site-name"><?php esc_html_e( 'Site Name', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-domain"><?php esc_html_e( 'Domain', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-primary"><?php esc_html_e( 'Primary', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col" class="column-actions"><?php esc_html_e( 'Actions', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $rows as $row ) :
|
||||
$site_name = get_blog_option( $row->blog_id, 'blogname', esc_html__( 'Unknown', 'wp-domain-mapping' ) );
|
||||
?>
|
||||
<tr>
|
||||
<th scope="row" class="check-column">
|
||||
<input type="checkbox" class="domain-checkbox" value="<?php echo esc_attr( $row->domain ); ?>" />
|
||||
</th>
|
||||
<td class="column-site-id">
|
||||
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'editblog', 'id' => $row->blog_id ), $edit_url ) ); ?>">
|
||||
<?php echo esc_html( $row->blog_id ); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td class="column-site-name">
|
||||
<?php echo esc_html( $site_name ); ?>
|
||||
</td>
|
||||
<td class="column-domain">
|
||||
<a href="<?php echo esc_url( dm_ensure_protocol( $row->domain ) ); ?>" target="_blank">
|
||||
<?php echo esc_html( $row->domain ); ?>
|
||||
<span class="dashicons dashicons-external" style="font-size: 14px; line-height: 1.3; opacity: 0.7;"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td class="column-primary">
|
||||
<?php if ( $row->active == 1 ) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Yes', 'wp-domain-mapping' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'No', 'wp-domain-mapping' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="column-actions">
|
||||
<div class="row-actions">
|
||||
<span class="edit">
|
||||
<a href="<?php echo esc_url( add_query_arg( array( 'edit_domain' => $row->domain ), admin_url( 'network/sites.php?page=domains' ) ) ); ?>" class="button button-small">
|
||||
<?php esc_html_e( 'Edit', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
</span>
|
||||
<?php if ( $row->active != 1 ) : ?>
|
||||
<span class="delete">
|
||||
<a href="#" class="button button-small domain-delete-button" data-domain="<?php echo esc_attr( $row->domain ); ?>">
|
||||
<?php esc_html_e( 'Delete', 'wp-domain-mapping' ); ?>
|
||||
</a>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
// Handle select all checkbox
|
||||
$('#select-all').on('change', function() {
|
||||
$('.domain-checkbox').prop('checked', this.checked);
|
||||
});
|
||||
|
||||
// Handle individual checkboxes
|
||||
$('.domain-checkbox').on('change', function() {
|
||||
if (!this.checked) {
|
||||
$('#select-all').prop('checked', false);
|
||||
} else if ($('.domain-checkbox:checked').length === $('.domain-checkbox').length) {
|
||||
$('#select-all').prop('checked', true);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle delete button clicks
|
||||
$('.domain-delete-button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (confirm('<?php esc_html_e( 'Are you sure you want to delete this domain?', 'wp-domain-mapping' ); ?>')) {
|
||||
var domain = $(this).data('domain');
|
||||
var data = {
|
||||
action: 'dm_handle_actions',
|
||||
action_type: 'delete',
|
||||
domain: domain,
|
||||
nonce: '<?php echo wp_create_nonce( 'domain_mapping' ); ?>'
|
||||
};
|
||||
|
||||
$.post(ajaxurl, data, function(response) {
|
||||
if (response.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
|
||||
if ( get_site_option( 'dm_no_primary_domain' ) == 1 ) {
|
||||
echo '<div class="notice notice-warning inline"><p>' .
|
||||
esc_html__( 'Warning! Primary domains are currently disabled in network settings.', 'wp-domain-mapping' ) .
|
||||
'</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure URL has a protocol
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
* @return string Domain with protocol
|
||||
*/
|
||||
function dm_ensure_protocol( $domain ) {
|
||||
if ( preg_match( '#^https?://#', $domain ) ) {
|
||||
return $domain;
|
||||
}
|
||||
return 'http://' . $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean domain name (remove protocol and trailing slash)
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
* @return string Cleaned domain
|
||||
*/
|
||||
function dm_clean_domain( $domain ) {
|
||||
// Remove protocol
|
||||
$domain = preg_replace( '#^https?://#', '', $domain );
|
||||
|
||||
// Remove trailing slash
|
||||
$domain = rtrim( $domain, '/' );
|
||||
|
||||
// Convert IDN to ASCII (Punycode)
|
||||
if ( function_exists( 'idn_to_ascii' ) && preg_match( '/[^a-z0-9\-\.]/i', $domain ) ) {
|
||||
if (defined('INTL_IDNA_VARIANT_UTS46')) {
|
||||
// PHP 7.2+
|
||||
$domain = idn_to_ascii( $domain, 0, INTL_IDNA_VARIANT_UTS46 );
|
||||
} else {
|
||||
// PHP < 7.2
|
||||
$domain = idn_to_ascii( $domain );
|
||||
}
|
||||
}
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display IDN warning message
|
||||
*
|
||||
* @return string Warning message
|
||||
*/
|
||||
function dm_idn_warning() {
|
||||
return sprintf(
|
||||
/* translators: %s: URL to punycode converter */
|
||||
wp_kses(
|
||||
__( 'International Domain Names should be in <a href="%s" target="_blank">punycode</a> format.', 'wp-domain-mapping' ),
|
||||
array( 'a' => array( 'href' => array(), 'target' => array() ) )
|
||||
),
|
||||
'https://www.punycoder.com/'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render domain logs table
|
||||
*/
|
||||
function dm_domain_logs() {
|
||||
global $wpdb;
|
||||
|
||||
$table_logs = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_LOGS;
|
||||
|
||||
// Make sure the table exists
|
||||
if ($wpdb->get_var("SHOW TABLES LIKE '$table_logs'") != $table_logs) {
|
||||
echo '<div class="notice notice-error"><p>' .
|
||||
esc_html__('Domain mapping logs table is missing. Please deactivate and reactivate the plugin.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$logs = $wpdb->get_results( "SELECT * FROM {$table_logs} ORDER BY timestamp DESC LIMIT 50" );
|
||||
|
||||
if ( ! $logs ) {
|
||||
echo '<div class="notice notice-info"><p>' . esc_html__( 'No logs available.', 'wp-domain-mapping' ) . '</p></div>';
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<table class="wp-list-table widefat striped logs-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><?php esc_html_e( 'User', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col"><?php esc_html_e( 'Action', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col"><?php esc_html_e( 'Domain', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col"><?php esc_html_e( 'Site ID', 'wp-domain-mapping' ); ?></th>
|
||||
<th scope="col"><?php esc_html_e( 'Timestamp', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $logs as $log ) :
|
||||
$user_data = get_userdata( $log->user_id );
|
||||
$username = $user_data ? $user_data->user_login : sprintf( __( 'User #%d', 'wp-domain-mapping' ), $log->user_id );
|
||||
|
||||
// Format action for display
|
||||
switch ( $log->action ) {
|
||||
case 'add':
|
||||
$action_display = '<span class="log-action log-action-add">' . __( 'Added', 'wp-domain-mapping' ) . '</span>';
|
||||
break;
|
||||
case 'edit':
|
||||
$action_display = '<span class="log-action log-action-edit">' . __( 'Updated', 'wp-domain-mapping' ) . '</span>';
|
||||
break;
|
||||
case 'delete':
|
||||
$action_display = '<span class="log-action log-action-delete">' . __( 'Deleted', 'wp-domain-mapping' ) . '</span>';
|
||||
break;
|
||||
default:
|
||||
$action_display = '<span class="log-action">' . esc_html( $log->action ) . '</span>';
|
||||
}
|
||||
|
||||
// Format timestamp for display
|
||||
$timestamp = mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $log->timestamp );
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( $username ); ?></td>
|
||||
<td><?php echo $action_display; ?></td>
|
||||
<td><?php echo esc_html( $log->domain ); ?></td>
|
||||
<td>
|
||||
<a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $log->blog_id ) ); ?>">
|
||||
<?php echo esc_html( $log->blog_id ); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td title="<?php echo esc_attr( $log->timestamp ); ?>">
|
||||
<?php echo esc_html( $timestamp ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<style>
|
||||
.log-action {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.log-action-add {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
}
|
||||
.log-action-edit {
|
||||
background-color: #d9edf7;
|
||||
color: #31708f;
|
||||
}
|
||||
.log-action-delete {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
897
includes/class-health.php
Normal file
897
includes/class-health.php
Normal file
|
@ -0,0 +1,897 @@
|
|||
<?php
|
||||
/**
|
||||
* 域名健康监控功能
|
||||
*
|
||||
* 处理域名健康状态检查和通知
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// 防止直接访问
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 域名健康监控类
|
||||
*/
|
||||
class WP_Domain_Mapping_Health {
|
||||
|
||||
/**
|
||||
* 类实例
|
||||
*
|
||||
* @var WP_Domain_Mapping_Health
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* 数据库实例
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* 获取类实例
|
||||
*
|
||||
* @return WP_Domain_Mapping_Health
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->db = WP_Domain_Mapping_DB::get_instance();
|
||||
|
||||
// 添加菜单页面
|
||||
add_action('network_admin_menu', array($this, 'add_menu_page'), 30);
|
||||
|
||||
// 添加AJAX处理程序
|
||||
add_action('wp_ajax_dm_check_domain_health', array($this, 'ajax_check_domain_health'));
|
||||
|
||||
// 添加计划任务钩子
|
||||
add_action('dm_domain_health_check', array($this, 'scheduled_health_check'));
|
||||
|
||||
// 初始化计划任务
|
||||
$this->initialize_cron();
|
||||
|
||||
// 处理手动健康检查
|
||||
add_action('admin_init', array($this, 'handle_manual_check'));
|
||||
|
||||
// 处理设置保存
|
||||
add_action('admin_init', array($this, 'handle_settings_save'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化定时健康检查
|
||||
*/
|
||||
private function initialize_cron() {
|
||||
// 注册激活时的钩子
|
||||
register_activation_hook(WP_DOMAIN_MAPPING_BASENAME, array($this, 'schedule_health_check'));
|
||||
|
||||
// 注册停用时的钩子
|
||||
register_deactivation_hook(WP_DOMAIN_MAPPING_BASENAME, array($this, 'unschedule_health_check'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加健康监控菜单
|
||||
*/
|
||||
public function add_menu_page() {
|
||||
add_submenu_page(
|
||||
'settings.php',
|
||||
__('Domain Health', 'wp-domain-mapping'),
|
||||
__('Domain Health', 'wp-domain-mapping'),
|
||||
'manage_network',
|
||||
'domain-mapping-health',
|
||||
array($this, 'render_page')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划健康检查任务
|
||||
*/
|
||||
public function schedule_health_check() {
|
||||
if (!wp_next_scheduled('dm_domain_health_check')) {
|
||||
wp_schedule_event(time(), 'daily', 'dm_domain_health_check');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消健康检查任务
|
||||
*/
|
||||
public function unschedule_health_check() {
|
||||
$timestamp = wp_next_scheduled('dm_domain_health_check');
|
||||
if ($timestamp) {
|
||||
wp_unschedule_event($timestamp, 'dm_domain_health_check');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理手动健康检查
|
||||
*/
|
||||
public function handle_manual_check() {
|
||||
if (isset($_POST['dm_manual_health_check']) && $_POST['dm_manual_health_check']) {
|
||||
// 验证nonce
|
||||
if (!isset($_POST['dm_manual_health_check_nonce']) || !wp_verify_nonce($_POST['dm_manual_health_check_nonce'], 'dm_manual_health_check')) {
|
||||
wp_die(__('Security check failed.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to perform this action.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 执行健康检查
|
||||
$this->run_health_check_for_all_domains();
|
||||
|
||||
// 重定向回健康页面
|
||||
wp_redirect(add_query_arg(array('page' => 'domain-mapping-health', 'checked' => 1), network_admin_url('settings.php')));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设置保存
|
||||
*/
|
||||
public function handle_settings_save() {
|
||||
if (isset($_POST['dm_health_settings']) && $_POST['dm_health_settings']) {
|
||||
// 验证nonce
|
||||
if (!isset($_POST['dm_health_settings_nonce']) || !wp_verify_nonce($_POST['dm_health_settings_nonce'], 'dm_health_settings')) {
|
||||
wp_die(__('Security check failed.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to perform this action.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 保存设置
|
||||
$health_check_enabled = isset($_POST['health_check_enabled']) ? (bool) $_POST['health_check_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']) : '';
|
||||
$ssl_expiry_threshold = isset($_POST['ssl_expiry_threshold']) ? intval($_POST['ssl_expiry_threshold']) : 14;
|
||||
|
||||
update_site_option('dm_health_check_enabled', $health_check_enabled);
|
||||
update_site_option('dm_health_notifications_enabled', $health_notifications_enabled);
|
||||
update_site_option('dm_notification_email', $notification_email);
|
||||
update_site_option('dm_ssl_expiry_threshold', $ssl_expiry_threshold);
|
||||
|
||||
// 如果启用了自动检查,确保计划任务已设置
|
||||
if ($health_check_enabled) {
|
||||
$this->schedule_health_check();
|
||||
} else {
|
||||
$this->unschedule_health_check();
|
||||
}
|
||||
|
||||
// 重定向回健康页面
|
||||
wp_redirect(add_query_arg(array('page' => 'domain-mapping-health', 'settings-updated' => 1), network_admin_url('settings.php')));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染健康监控页面
|
||||
*/
|
||||
public function render_page() {
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to access this page.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 获取所有域名
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
$domains = $wpdb->get_results("
|
||||
SELECT d.*, b.domain as original_domain, b.path
|
||||
FROM {$table} d
|
||||
JOIN {$wpdb->blogs} b ON d.blog_id = b.blog_id
|
||||
ORDER BY d.blog_id ASC, d.active DESC
|
||||
");
|
||||
|
||||
// 获取健康检查结果(如果有)
|
||||
$health_results = get_site_option('dm_domain_health_results', array());
|
||||
|
||||
// 渲染页面
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
|
||||
<?php
|
||||
// 显示成功消息(如果有)
|
||||
if (isset($_GET['checked']) && $_GET['checked']) {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__('Domain health check completed.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
}
|
||||
|
||||
if (isset($_GET['settings-updated']) && $_GET['settings-updated']) {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__('Settings saved.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="card domain-mapping-card" style="max-width: 100%; margin-top: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
|
||||
<h2><?php _e('Domain Health Status', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<?php if ($health_data) : ?>
|
||||
<button type="button" class="button button-small show-health-details" data-domain="<?php echo esc_attr($domain->domain); ?>">
|
||||
<?php _e('Details', 'wp-domain-mapping'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ($health_data) : ?>
|
||||
<tr class="health-details-row" id="health-details-<?php echo esc_attr($domain_key); ?>" style="display: none;">
|
||||
<td colspan="7">
|
||||
<div class="health-details-content">
|
||||
<h4><?php echo sprintf(__('Health Details for %s', 'wp-domain-mapping'), esc_html($domain->domain)); ?></h4>
|
||||
|
||||
<table class="widefat striped" style="margin-top: 10px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?php _e('Last Check', 'wp-domain-mapping'); ?></th>
|
||||
<td><?php echo isset($health_data['last_check']) ? esc_html(date('Y-m-d H:i:s', strtotime($health_data['last_check']))) : '-'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('DNS Status', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<?php if (isset($health_data['dns_status'])) : ?>
|
||||
<?php if ($health_data['dns_status'] === 'success') : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php _e('DNS correctly configured', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-warning" style="color: #dc3232;"></span>
|
||||
<?php echo esc_html($health_data['dns_message']); ?>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<?php _e('Not checked', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('Resolved IP', 'wp-domain-mapping'); ?></th>
|
||||
<td><?php echo isset($health_data['resolved_ip']) ? esc_html($health_data['resolved_ip']) : '-'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('SSL Valid', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<?php if (isset($health_data['ssl_valid'])) : ?>
|
||||
<?php if ($health_data['ssl_valid']) : ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php _e('Valid', 'wp-domain-mapping'); ?>
|
||||
<?php else : ?>
|
||||
<span class="dashicons dashicons-warning" style="color: #dc3232;"></span>
|
||||
<?php _e('Invalid', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<?php _e('Not checked', 'wp-domain-mapping'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('SSL Expiry', 'wp-domain-mapping'); ?></th>
|
||||
<td><?php echo isset($health_data['ssl_expiry']) ? esc_html(date('Y-m-d', strtotime($health_data['ssl_expiry']))) : '-'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php _e('Response Code', 'wp-domain-mapping'); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
if (isset($health_data['response_code'])) {
|
||||
echo esc_html($health_data['response_code']);
|
||||
if ($health_data['response_code'] >= 200 && $health_data['response_code'] < 400) {
|
||||
echo ' <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>';
|
||||
} else {
|
||||
echo ' <span class="dashicons dashicons-warning" style="color: #dc3232;"></span>';
|
||||
}
|
||||
} else {
|
||||
echo '-';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="7"><?php _e('No domains found.', 'wp-domain-mapping'); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card" style="max-width: 100%; margin-top: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
|
||||
<h2><?php _e('Health Check Settings', 'wp-domain-mapping'); ?></h2>
|
||||
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
// 单个域名健康检查
|
||||
$('.check-domain-health').on('click', function() {
|
||||
var $button = $(this);
|
||||
var domain = $button.data('domain');
|
||||
var $row = $button.closest('tr');
|
||||
|
||||
$button.prop('disabled', true).text('<?php esc_html_e('Checking...', 'wp-domain-mapping'); ?>');
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
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) {
|
||||
// 刷新页面以显示更新的结果
|
||||
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('<?php esc_html_e('Check Now', 'wp-domain-mapping'); ?>');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('<?php esc_html_e('An error occurred during the health check.', 'wp-domain-mapping'); ?>');
|
||||
$button.prop('disabled', false).text('<?php esc_html_e('Check Now', 'wp-domain-mapping'); ?>');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 显示/隐藏健康详情
|
||||
$('.show-health-details').on('click', function() {
|
||||
var domain = $(this).data('domain');
|
||||
var domainKey = md5(domain);
|
||||
$('#health-details-' + domainKey).toggle();
|
||||
});
|
||||
|
||||
// 简单MD5函数 (用于生成域名的唯一ID)
|
||||
function md5(string) {
|
||||
function md5cycle(x, k) {
|
||||
var a = x[0], b = x[1], c = x[2], d = x[3];
|
||||
|
||||
a = ff(a, b, c, d, k[0], 7, -680876936);
|
||||
d = ff(d, a, b, c, k[1], 12, -389564586);
|
||||
c = ff(c, d, a, b, k[2], 17, 606105819);
|
||||
b = ff(b, c, d, a, k[3], 22, -1044525330);
|
||||
// ...其余MD5算法...
|
||||
|
||||
x[0] = add32(a, x[0]);
|
||||
x[1] = add32(b, x[1]);
|
||||
x[2] = add32(c, x[2]);
|
||||
x[3] = add32(d, x[3]);
|
||||
}
|
||||
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
a = add32(add32(a, q), add32(x, t));
|
||||
return add32((a << s) | (a >>> (32 - s)), b);
|
||||
}
|
||||
|
||||
function ff(a, b, c, d, x, s, t) {
|
||||
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
||||
}
|
||||
|
||||
function add32(a, b) {
|
||||
return (a + b) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
// 简化版本,仅用于客户端显示目的
|
||||
var hash = 0;
|
||||
if (string.length === 0) return hash;
|
||||
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
var char = string.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash; // 转换为32位整数
|
||||
}
|
||||
|
||||
return Math.abs(hash).toString(16);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX处理域名健康检查
|
||||
*/
|
||||
public function ajax_check_domain_health() {
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_send_json_error(__('You do not have sufficient permissions to perform this action.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 验证nonce
|
||||
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'dm_check_domain_health')) {
|
||||
wp_send_json_error(__('Security check failed.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 获取域名
|
||||
$domain = isset($_POST['domain']) ? sanitize_text_field($_POST['domain']) : '';
|
||||
if (empty($domain)) {
|
||||
wp_send_json_error(__('No domain specified.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 执行健康检查
|
||||
$result = $this->check_domain_health($domain);
|
||||
|
||||
// 保存结果
|
||||
$this->save_health_check_result($domain, $result);
|
||||
|
||||
// 返回结果
|
||||
wp_send_json_success($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划任务:执行所有域名健康检查
|
||||
*/
|
||||
public function scheduled_health_check() {
|
||||
// 检查是否启用了自动健康检查
|
||||
if (!get_site_option('dm_health_check_enabled', true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->run_health_check_for_all_domains();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对所有域名执行健康检查
|
||||
*/
|
||||
private function run_health_check_for_all_domains() {
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
|
||||
// 获取所有域名
|
||||
$domains = $wpdb->get_col("SELECT domain FROM {$table}");
|
||||
|
||||
// 初始化通知信息
|
||||
$issues = array();
|
||||
|
||||
// 检查每个域名
|
||||
foreach ($domains as $domain) {
|
||||
$result = $this->check_domain_health($domain);
|
||||
$this->save_health_check_result($domain, $result);
|
||||
|
||||
// 检查是否有问题
|
||||
if ($this->has_health_issues($result)) {
|
||||
$issues[$domain] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果启用了通知并且有问题,发送通知
|
||||
if (!empty($issues) && get_site_option('dm_health_notifications_enabled', true)) {
|
||||
$this->send_health_notification($issues);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查域名健康状态
|
||||
*
|
||||
* @param string $domain 要检查的域名
|
||||
* @return array 健康检查结果
|
||||
*/
|
||||
private function check_domain_health($domain) {
|
||||
$result = array(
|
||||
'domain' => $domain,
|
||||
'last_check' => current_time('mysql'),
|
||||
'dns_status' => 'error',
|
||||
'dns_message' => __('DNS check not performed', 'wp-domain-mapping'),
|
||||
'resolved_ip' => '',
|
||||
'ssl_valid' => false,
|
||||
'ssl_expiry' => '',
|
||||
'accessible' => false,
|
||||
'response_code' => 0
|
||||
);
|
||||
|
||||
// 获取服务器IP或CNAME
|
||||
$server_ip = get_site_option('dm_ipaddress', '');
|
||||
$server_cname = get_site_option('dm_cname', '');
|
||||
|
||||
// 检查DNS设置
|
||||
$domain_ip = gethostbyname($domain);
|
||||
$result['resolved_ip'] = $domain_ip;
|
||||
|
||||
if ($domain_ip && $domain_ip !== $domain) {
|
||||
if ($server_ip && strpos($server_ip, $domain_ip) !== false) {
|
||||
$result['dns_status'] = 'success';
|
||||
$result['dns_message'] = __('Domain A record is correctly pointing to server IP.', 'wp-domain-mapping');
|
||||
} elseif ($server_cname && function_exists('dns_get_record')) {
|
||||
$dns_records = @dns_get_record($domain, DNS_CNAME);
|
||||
$has_valid_cname = false;
|
||||
|
||||
if ($dns_records) {
|
||||
foreach ($dns_records as $record) {
|
||||
if (isset($record['target']) &&
|
||||
(
|
||||
$record['target'] === $server_cname ||
|
||||
strpos($record['target'], $server_cname) !== false
|
||||
)) {
|
||||
$has_valid_cname = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_valid_cname) {
|
||||
$result['dns_status'] = 'success';
|
||||
$result['dns_message'] = __('Domain CNAME record is correctly configured.', 'wp-domain-mapping');
|
||||
} else {
|
||||
$result['dns_message'] = __('Domain is not pointing to the correct server.', 'wp-domain-mapping');
|
||||
}
|
||||
} else {
|
||||
$result['dns_message'] = __('Cannot verify DNS configuration.', 'wp-domain-mapping');
|
||||
}
|
||||
} else {
|
||||
$result['dns_message'] = __('Domain does not resolve to an IP address.', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// 检查网站可访问性和SSL
|
||||
$response = $this->test_domain_connection($domain);
|
||||
|
||||
if ($response) {
|
||||
$result['accessible'] = $response['accessible'];
|
||||
$result['response_code'] = $response['response_code'];
|
||||
$result['ssl_valid'] = $response['ssl_valid'];
|
||||
$result['ssl_expiry'] = $response['ssl_expiry'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试域名连接
|
||||
*
|
||||
* @param string $domain 域名
|
||||
* @return array|false 连接测试结果
|
||||
*/
|
||||
private function test_domain_connection($domain) {
|
||||
if (!function_exists('curl_init')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'accessible' => false,
|
||||
'response_code' => 0,
|
||||
'ssl_valid' => false,
|
||||
'ssl_expiry' => ''
|
||||
);
|
||||
|
||||
// 测试HTTPS连接
|
||||
$ch = curl_init('https://' . $domain);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$result['response_code'] = $response_code;
|
||||
|
||||
if ($response !== false && $response_code > 0) {
|
||||
$result['accessible'] = ($response_code >= 200 && $response_code < 400);
|
||||
$result['ssl_valid'] = ($response !== false);
|
||||
|
||||
// 获取SSL证书信息
|
||||
$ssl_info = curl_getinfo($ch, CURLINFO_CERTINFO);
|
||||
if (!empty($ssl_info) && isset($ssl_info[0]['Expire date'])) {
|
||||
$result['ssl_expiry'] = $ssl_info[0]['Expire date'];
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// 如果HTTPS失败,尝试HTTP
|
||||
if (!$result['accessible']) {
|
||||
$ch = curl_init('http://' . $domain);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if ($response !== false && $response_code > 0) {
|
||||
$result['accessible'] = ($response_code >= 200 && $response_code < 400);
|
||||
$result['response_code'] = $response_code;
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存健康检查结果
|
||||
*
|
||||
* @param string $domain 域名
|
||||
* @param array $result 健康检查结果
|
||||
*/
|
||||
private function save_health_check_result($domain, $result) {
|
||||
$health_results = get_site_option('dm_domain_health_results', array());
|
||||
$domain_key = md5($domain);
|
||||
|
||||
$health_results[$domain_key] = $result;
|
||||
update_site_option('dm_domain_health_results', $health_results);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查结果是否有健康问题
|
||||
*
|
||||
* @param array $result 健康检查结果
|
||||
* @return bool 是否有问题
|
||||
*/
|
||||
private function has_health_issues($result) {
|
||||
// 检查DNS问题
|
||||
if ($result['dns_status'] !== 'success') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查SSL问题
|
||||
if (!$result['ssl_valid']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查SSL即将到期
|
||||
if (!empty($result['ssl_expiry'])) {
|
||||
$expiry_date = strtotime($result['ssl_expiry']);
|
||||
$threshold = get_site_option('dm_ssl_expiry_threshold', 14);
|
||||
$threshold_date = strtotime('+' . $threshold . ' days');
|
||||
|
||||
if ($expiry_date <= $threshold_date) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查可访问性问题
|
||||
if (!$result['accessible']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送健康问题通知
|
||||
*
|
||||
* @param array $issues 有问题的域名及其健康检查结果
|
||||
*/
|
||||
private function send_health_notification($issues) {
|
||||
$notification_email = get_site_option('dm_notification_email', get_option('admin_email'));
|
||||
|
||||
if (empty($notification_email)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$site_name = get_bloginfo('name');
|
||||
$subject = sprintf(__('[%s] Domain Mapping Health Alert', 'wp-domain-mapping'), $site_name);
|
||||
|
||||
// 构建邮件内容
|
||||
$message = sprintf(__('Domain health issues were detected on %s.', 'wp-domain-mapping'), $site_name) . "\n\n";
|
||||
$message .= __('The following domains have issues:', 'wp-domain-mapping') . "\n\n";
|
||||
|
||||
foreach ($issues as $domain => $result) {
|
||||
$message .= sprintf(__('Domain: %s', 'wp-domain-mapping'), $domain) . "\n";
|
||||
|
||||
// 添加DNS状态
|
||||
if ($result['dns_status'] !== 'success') {
|
||||
$message .= " - " . sprintf(__('DNS Issue: %s', 'wp-domain-mapping'), $result['dns_message']) . "\n";
|
||||
}
|
||||
|
||||
// 添加SSL状态
|
||||
if (!$result['ssl_valid']) {
|
||||
$message .= " - " . __('SSL Certificate is invalid or missing.', 'wp-domain-mapping') . "\n";
|
||||
} elseif (!empty($result['ssl_expiry'])) {
|
||||
$expiry_date = strtotime($result['ssl_expiry']);
|
||||
$threshold = get_site_option('dm_ssl_expiry_threshold', 14);
|
||||
$threshold_date = strtotime('+' . $threshold . ' days');
|
||||
|
||||
if ($expiry_date <= $threshold_date) {
|
||||
$message .= " - " . sprintf(
|
||||
__('SSL Certificate expires on %s (within %d days).', 'wp-domain-mapping'),
|
||||
date('Y-m-d', $expiry_date),
|
||||
$threshold
|
||||
) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 添加可访问性状态
|
||||
if (!$result['accessible']) {
|
||||
$message .= " - " . __('Site is not accessible.', 'wp-domain-mapping') . "\n";
|
||||
if ($result['response_code'] > 0) {
|
||||
$message .= " " . sprintf(__('HTTP Response Code: %d', 'wp-domain-mapping'), $result['response_code']) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$message .= "\n";
|
||||
}
|
||||
|
||||
// 添加解决方案链接
|
||||
$message .= sprintf(
|
||||
__('To view and manage these issues, please visit: %s', 'wp-domain-mapping'),
|
||||
network_admin_url('settings.php?page=domain-mapping-health')
|
||||
) . "\n";
|
||||
|
||||
// 发送邮件
|
||||
wp_mail($notification_email, $subject, $message);
|
||||
}
|
||||
}
|
592
includes/class-importer.php
Normal file
592
includes/class-importer.php
Normal file
|
@ -0,0 +1,592 @@
|
|||
<?php
|
||||
/**
|
||||
* 域名映射导入/导出功能
|
||||
*
|
||||
* 处理域名映射的批量导入和导出
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// 防止直接访问
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 域名映射导入/导出类
|
||||
*/
|
||||
class WP_Domain_Mapping_Importer {
|
||||
|
||||
/**
|
||||
* 类实例
|
||||
*
|
||||
* @var WP_Domain_Mapping_Importer
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* 数据库实例
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* 获取类实例
|
||||
*
|
||||
* @return WP_Domain_Mapping_Importer
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->db = WP_Domain_Mapping_DB::get_instance();
|
||||
|
||||
// 添加菜单页面
|
||||
add_action('network_admin_menu', array($this, 'add_menu_page'), 20);
|
||||
|
||||
// 处理表单提交
|
||||
add_action('admin_init', array($this, 'handle_form_submission'));
|
||||
|
||||
// AJAX处理程序
|
||||
add_action('wp_ajax_dm_import_csv', array($this, 'ajax_import_csv'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加导入/导出菜单
|
||||
*/
|
||||
public function add_menu_page() {
|
||||
add_submenu_page(
|
||||
'settings.php',
|
||||
__('Import/Export Domains', 'wp-domain-mapping'),
|
||||
__('Import/Export Domains', 'wp-domain-mapping'),
|
||||
'manage_network',
|
||||
'domain-mapping-import-export',
|
||||
array($this, 'render_page')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染导入/导出页面
|
||||
*/
|
||||
public function render_page() {
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to access this page.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 输出成功消息(如果有)
|
||||
if (isset($_GET['imported']) && $_GET['imported']) {
|
||||
$count = intval($_GET['imported']);
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
sprintf(
|
||||
_n(
|
||||
'%d domain mapping imported successfully.',
|
||||
'%d domain mappings imported successfully.',
|
||||
$count,
|
||||
'wp-domain-mapping'
|
||||
),
|
||||
$count
|
||||
) .
|
||||
'</p></div>';
|
||||
}
|
||||
|
||||
if (isset($_GET['export']) && $_GET['export'] == 'success') {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__('Domain mappings exported successfully.', 'wp-domain-mapping') .
|
||||
'</p></div>';
|
||||
}
|
||||
|
||||
// 显示页面
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
|
||||
<div class="card domain-mapping-card" style="max-width: 100%; margin-top: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
|
||||
<h2><?php _e('Export Domain Mappings', 'wp-domain-mapping'); ?></h2>
|
||||
<p><?php _e('Export all domain mappings to a CSV file.', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('domain_mapping_export', 'domain_mapping_export_nonce'); ?>
|
||||
<input type="hidden" name="domain_mapping_export" value="1">
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="include_header" value="1" checked>
|
||||
<?php _e('Include column headers', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="blog_id_filter"><?php _e('Export for specific site ID (optional):', 'wp-domain-mapping'); ?></label>
|
||||
<input type="number" id="blog_id_filter" name="blog_id_filter" min="1" class="regular-text">
|
||||
<p class="description"><?php _e('Leave empty to export all domains.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e('Export to CSV', 'wp-domain-mapping'); ?>">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card" style="max-width: 100%; margin-top: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
|
||||
<h2><?php _e('Import Domain Mappings', 'wp-domain-mapping'); ?></h2>
|
||||
<p><?php _e('Import domain mappings from a CSV file.', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<form method="post" enctype="multipart/form-data" id="domain-mapping-import-form">
|
||||
<?php wp_nonce_field('domain_mapping_import', 'domain_mapping_import_nonce'); ?>
|
||||
<input type="hidden" name="domain_mapping_import" value="1">
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="csv_file"><?php _e('CSV File:', 'wp-domain-mapping'); ?></label><br>
|
||||
<input type="file" id="csv_file" name="csv_file" accept=".csv" required>
|
||||
<p class="description">
|
||||
<?php _e('The CSV file should have the columns: blog_id, domain, active (1 or 0).', 'wp-domain-mapping'); ?><br>
|
||||
<?php _e('Example: 1,example.com,1', 'wp-domain-mapping'); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="has_header" value="1" checked>
|
||||
<?php _e('First row contains column headers', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="update_existing" value="1" checked>
|
||||
<?php _e('Update existing mappings', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description"><?php _e('If unchecked, will skip domains that already exist.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox" name="validate_sites" value="1" checked>
|
||||
<?php _e('Validate site IDs', 'wp-domain-mapping'); ?>
|
||||
</label>
|
||||
<p class="description"><?php _e('If checked, will only import domains for existing sites.', 'wp-domain-mapping'); ?></p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<input type="submit" class="button button-primary" value="<?php esc_attr_e('Import from CSV', 'wp-domain-mapping'); ?>">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<div id="import-progress" style="display: none; margin-top: 20px;">
|
||||
<p><?php _e('Processing import...', 'wp-domain-mapping'); ?></p>
|
||||
<div class="progress-bar-outer" style="background-color: #f0f0f1; border-radius: 4px; height: 20px; width: 100%; overflow: hidden;">
|
||||
<div class="progress-bar-inner" style="background-color: #2271b1; height: 100%; width: 0%;"></div>
|
||||
</div>
|
||||
<p class="progress-text">0%</p>
|
||||
</div>
|
||||
|
||||
<div id="import-results" style="display: none; margin-top: 20px;">
|
||||
<h3><?php _e('Import Results', 'wp-domain-mapping'); ?></h3>
|
||||
<div class="import-summary"></div>
|
||||
<div class="import-details"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card" style="max-width: 100%; margin-top: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
|
||||
<h2><?php _e('CSV Format', 'wp-domain-mapping'); ?></h2>
|
||||
<p><?php _e('The CSV file should follow this format:', 'wp-domain-mapping'); ?></p>
|
||||
|
||||
<table class="widefat" style="margin-top: 10px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>blog_id</th>
|
||||
<th>domain</th>
|
||||
<th>active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>example.com</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>example.org</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ul style="margin-top: 15px;">
|
||||
<li><strong>blog_id</strong>: <?php _e('The ID of the WordPress site (required)', 'wp-domain-mapping'); ?></li>
|
||||
<li><strong>domain</strong>: <?php _e('The domain name without http:// or https:// (required)', 'wp-domain-mapping'); ?></li>
|
||||
<li><strong>active</strong>: <?php _e('Set to 1 to make this the primary domain, 0 otherwise (required)', 'wp-domain-mapping'); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
$('#domain-mapping-import-form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var formData = new FormData(this);
|
||||
formData.append('action', 'dm_import_csv');
|
||||
|
||||
// 显示进度条
|
||||
$('#import-progress').show();
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: function(response) {
|
||||
// 隐藏进度条
|
||||
$('#import-progress').hide();
|
||||
|
||||
// 显示结果
|
||||
$('#import-results').show();
|
||||
|
||||
if (response.success) {
|
||||
$('.import-summary').html(
|
||||
'<div class="notice notice-success"><p>' +
|
||||
response.data.message +
|
||||
'</p></div>'
|
||||
);
|
||||
|
||||
var details = '<table class="widefat">' +
|
||||
'<thead><tr>' +
|
||||
'<th>Status</th>' +
|
||||
'<th>Details</th>' +
|
||||
'</tr></thead><tbody>';
|
||||
|
||||
$.each(response.data.details, function(i, item) {
|
||||
var statusClass = 'notice-success';
|
||||
if (item.status === 'error') {
|
||||
statusClass = 'notice-error';
|
||||
} else if (item.status === 'warning') {
|
||||
statusClass = 'notice-warning';
|
||||
}
|
||||
|
||||
details += '<tr class="' + statusClass + '">' +
|
||||
'<td>' + item.status + '</td>' +
|
||||
'<td>' + item.message + '</td>' +
|
||||
'</tr>';
|
||||
});
|
||||
|
||||
details += '</tbody></table>';
|
||||
$('.import-details').html(details);
|
||||
} else {
|
||||
$('.import-summary').html(
|
||||
'<div class="notice notice-error"><p>' +
|
||||
response.data +
|
||||
'</p></div>'
|
||||
);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// 隐藏进度条
|
||||
$('#import-progress').hide();
|
||||
|
||||
// 显示错误
|
||||
$('#import-results').show();
|
||||
$('.import-summary').html(
|
||||
'<div class="notice notice-error"><p>' +
|
||||
'<?php _e('An error occurred during import.', 'wp-domain-mapping'); ?>' +
|
||||
'</p></div>'
|
||||
);
|
||||
},
|
||||
xhr: function() {
|
||||
var xhr = new window.XMLHttpRequest();
|
||||
|
||||
// 上传进度
|
||||
xhr.upload.addEventListener('progress', function(evt) {
|
||||
if (evt.lengthComputable) {
|
||||
var percentComplete = evt.loaded / evt.total * 100;
|
||||
$('.progress-bar-inner').css('width', percentComplete + '%');
|
||||
$('.progress-text').text(Math.round(percentComplete) + '%');
|
||||
}
|
||||
}, false);
|
||||
|
||||
return xhr;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表单提交
|
||||
*/
|
||||
public function handle_form_submission() {
|
||||
// 处理导出
|
||||
if (isset($_POST['domain_mapping_export']) && $_POST['domain_mapping_export']) {
|
||||
$this->handle_export();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理CSV导出
|
||||
*/
|
||||
private function handle_export() {
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to export data.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 验证nonce
|
||||
if (!isset($_POST['domain_mapping_export_nonce']) || !wp_verify_nonce($_POST['domain_mapping_export_nonce'], 'domain_mapping_export')) {
|
||||
wp_die(__('Invalid security token. Please try again.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 获取选项
|
||||
$include_header = isset($_POST['include_header']) ? (bool) $_POST['include_header'] : false;
|
||||
$blog_id_filter = isset($_POST['blog_id_filter']) && !empty($_POST['blog_id_filter']) ? intval($_POST['blog_id_filter']) : 0;
|
||||
|
||||
// 获取域名映射数据
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
$sql = "SELECT blog_id, domain, active FROM {$table}";
|
||||
|
||||
if ($blog_id_filter > 0) {
|
||||
$sql .= $wpdb->prepare(" WHERE blog_id = %d", $blog_id_filter);
|
||||
}
|
||||
|
||||
$domains = $wpdb->get_results($sql, ARRAY_A);
|
||||
|
||||
if (empty($domains)) {
|
||||
// 没有数据
|
||||
wp_redirect(add_query_arg(array('page' => 'domain-mapping-import-export', 'export' => 'empty'), network_admin_url('settings.php')));
|
||||
exit;
|
||||
}
|
||||
|
||||
// 设置CSV输出
|
||||
$filename = 'domain-mappings-' . date('Y-m-d') . '.csv';
|
||||
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename=' . $filename);
|
||||
|
||||
$output = fopen('php://output', 'w');
|
||||
|
||||
// 添加标题行
|
||||
if ($include_header) {
|
||||
fputcsv($output, array('blog_id', 'domain', 'active'));
|
||||
}
|
||||
|
||||
// 添加数据行
|
||||
foreach ($domains as $domain) {
|
||||
fputcsv($output, $domain);
|
||||
}
|
||||
|
||||
fclose($output);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX处理CSV导入
|
||||
*/
|
||||
public function ajax_import_csv() {
|
||||
// 检查权限
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_send_json_error(__('You do not have sufficient permissions to import data.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 验证nonce
|
||||
if (!isset($_POST['domain_mapping_import_nonce']) || !wp_verify_nonce($_POST['domain_mapping_import_nonce'], 'domain_mapping_import')) {
|
||||
wp_send_json_error(__('Invalid security token. Please try again.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 检查文件
|
||||
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'));
|
||||
}
|
||||
|
||||
// 获取选项
|
||||
$has_header = isset($_POST['has_header']) ? (bool) $_POST['has_header'] : false;
|
||||
$update_existing = isset($_POST['update_existing']) ? (bool) $_POST['update_existing'] : false;
|
||||
$validate_sites = isset($_POST['validate_sites']) ? (bool) $_POST['validate_sites'] : true;
|
||||
|
||||
// 打开文件
|
||||
$file = fopen($_FILES['csv_file']['tmp_name'], 'r');
|
||||
if (!$file) {
|
||||
wp_send_json_error(__('Could not open the uploaded file.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// 初始化计数器和日志
|
||||
$imported = 0;
|
||||
$skipped = 0;
|
||||
$errors = 0;
|
||||
$log = array();
|
||||
|
||||
// 跳过标题行
|
||||
if ($has_header) {
|
||||
fgetcsv($file);
|
||||
}
|
||||
|
||||
// 处理每一行
|
||||
$core = WP_Domain_Mapping_Core::get_instance();
|
||||
$row_num = $has_header ? 2 : 1; // 考虑标题行
|
||||
|
||||
while (($data = fgetcsv($file)) !== false) {
|
||||
// 检查数据格式
|
||||
if (count($data) < 3) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Invalid format. Expected at least 3 columns.', 'wp-domain-mapping'), $row_num)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 解析数据
|
||||
$blog_id = intval($data[0]);
|
||||
$domain = $core->clean_domain(trim($data[1]));
|
||||
$active = intval($data[2]);
|
||||
|
||||
// 验证blog_id
|
||||
if ($blog_id <= 0) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Invalid blog ID: %d', 'wp-domain-mapping'), $row_num, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 验证站点是否存在
|
||||
if ($validate_sites && !get_blog_details($blog_id)) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Site ID %d does not exist.', 'wp-domain-mapping'), $row_num, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 验证域名格式
|
||||
if (!$core->validate_domain($domain)) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Invalid domain format: %s', 'wp-domain-mapping'), $row_num, $domain)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查域名是否已经存在于其他站点
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
$existing = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM $table WHERE domain = %s",
|
||||
$domain
|
||||
));
|
||||
|
||||
if ($existing) {
|
||||
if ($existing->blog_id != $blog_id) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Domain %s is already mapped to blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $existing->blog_id)
|
||||
);
|
||||
$errors++;
|
||||
} elseif (!$update_existing) {
|
||||
$log[] = array(
|
||||
'status' => 'warning',
|
||||
'message' => sprintf(__('Row %d: Domain %s already exists for blog ID %d. Skipped.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$skipped++;
|
||||
} else {
|
||||
// 更新现有域名
|
||||
$result = $wpdb->update(
|
||||
$table,
|
||||
array('active' => $active),
|
||||
array('domain' => $domain),
|
||||
array('%d'),
|
||||
array('%s')
|
||||
);
|
||||
|
||||
if ($result !== false) {
|
||||
$log[] = array(
|
||||
'status' => 'success',
|
||||
'message' => sprintf(__('Row %d: Updated domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$imported++;
|
||||
} else {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Failed to update domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 添加新域名
|
||||
$result = $wpdb->insert(
|
||||
$table,
|
||||
array(
|
||||
'blog_id' => $blog_id,
|
||||
'domain' => $domain,
|
||||
'active' => $active
|
||||
),
|
||||
array('%d', '%s', '%d')
|
||||
);
|
||||
|
||||
if ($result) {
|
||||
// 记录操作
|
||||
$this->db->log_action('import', $domain, $blog_id);
|
||||
|
||||
// 清除缓存
|
||||
$this->db->invalidate_domain_cache($blog_id);
|
||||
|
||||
$log[] = array(
|
||||
'status' => 'success',
|
||||
'message' => sprintf(__('Row %d: Added domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$imported++;
|
||||
} else {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Failed to add domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
|
||||
$row_num++;
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
|
||||
// 构建响应
|
||||
$message = sprintf(
|
||||
__('Import completed: %d imported, %d skipped, %d errors.', 'wp-domain-mapping'),
|
||||
$imported, $skipped, $errors
|
||||
);
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => $message,
|
||||
'imported' => $imported,
|
||||
'skipped' => $skipped,
|
||||
'errors' => $errors,
|
||||
'details' => $log
|
||||
));
|
||||
}
|
||||
}
|
132
includes/class-site-id.php
Normal file
132
includes/class-site-id.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
/**
|
||||
* 站点ID显示功能
|
||||
*
|
||||
* 显示当前WordPress多站点的站点ID
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
*/
|
||||
|
||||
// 防止直接访问
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WordPress站点ID显示类
|
||||
*
|
||||
* 基于WP Show Site ID插件 (by Emanuela Castorina)
|
||||
*/
|
||||
class WP_Domain_Mapping_Site_ID {
|
||||
|
||||
/**
|
||||
* 类实例
|
||||
*
|
||||
* @var WP_Domain_Mapping_Site_ID
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* 获取类实例
|
||||
*
|
||||
* @return WP_Domain_Mapping_Site_ID
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
private function __construct() {
|
||||
// 只在多站点环境中工作
|
||||
if (!is_multisite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加站点ID到WordPress工具栏
|
||||
add_action('admin_bar_menu', array($this, 'add_toolbar_items'), 100);
|
||||
|
||||
// 添加站点ID列到网络管理员的站点列表页面
|
||||
add_filter('manage_sites-network_columns', array($this, 'manage_sites_columns'), 20);
|
||||
add_action('manage_sites_custom_column', array($this, 'show_site_id'), 10, 2);
|
||||
add_action('admin_print_styles', array($this, 'custom_style'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加自定义样式
|
||||
*/
|
||||
public function custom_style() {
|
||||
if ('sites-network' == get_current_screen()->id) {
|
||||
?>
|
||||
<style type="text/css">
|
||||
th#dm_site_id { width: 3.5em; }
|
||||
.dm-site-id-badge {
|
||||
display: inline-block;
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向WordPress工具栏添加站点ID
|
||||
*
|
||||
* @param WP_Admin_Bar $admin_bar WordPress工具栏对象
|
||||
*/
|
||||
public function add_toolbar_items($admin_bar) {
|
||||
// 仅向管理员或网络管理员显示
|
||||
if (!current_user_can('manage_options') && !is_super_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
|
||||
$admin_bar->add_menu(array(
|
||||
'id' => 'wp-site-ID',
|
||||
'title' => sprintf(__('Site ID: %d', 'wp-domain-mapping'), $blog_id),
|
||||
'href' => is_super_admin() ? esc_url(network_admin_url('site-info.php?id=' . $blog_id)) : '#',
|
||||
'meta' => array(
|
||||
'title' => is_super_admin() ? __('Edit this site', 'wp-domain-mapping') : __('Current site ID', 'wp-domain-mapping'),
|
||||
'class' => 'dm-site-id-menu'
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 向站点列表添加ID列
|
||||
*
|
||||
* @param array $columns 当前列
|
||||
* @return array 修改后的列
|
||||
*/
|
||||
public function manage_sites_columns($columns) {
|
||||
// 在第一列后添加站点ID列
|
||||
$columns = array_slice($columns, 0, 1, true) +
|
||||
array('dm_site_id' => __('Site ID', 'wp-domain-mapping')) +
|
||||
array_slice($columns, 1, count($columns) - 1, true);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示站点ID列的内容
|
||||
*
|
||||
* @param string $column 列名
|
||||
* @param int $blog_id 站点ID
|
||||
*/
|
||||
public function show_site_id($column, $blog_id) {
|
||||
if ('dm_site_id' == $column) {
|
||||
echo '<span class="dm-site-id-badge">' . esc_html($blog_id) . '</span>';
|
||||
}
|
||||
}
|
||||
}
|
709
includes/class-tools.php
Normal file
709
includes/class-tools.php
Normal file
|
@ -0,0 +1,709 @@
|
|||
<?php
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WP_Domain_Mapping_Tools {
|
||||
private static $instance = null;
|
||||
private $db;
|
||||
private $core;
|
||||
|
||||
public static function get_instance() {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct() {
|
||||
$this->db = WP_Domain_Mapping_DB::get_instance();
|
||||
$this->core = WP_Domain_Mapping_Core::get_instance();
|
||||
|
||||
// Setup hooks
|
||||
$this->setup_hooks();
|
||||
}
|
||||
|
||||
private function setup_hooks() {
|
||||
// Add menu pages for tools
|
||||
add_action('network_admin_menu', array($this, 'add_menu_pages'), 20);
|
||||
|
||||
// Add Site ID to toolbar
|
||||
add_action('admin_bar_menu', array($this, 'add_site_id_to_toolbar'), 100);
|
||||
|
||||
// Add Site ID column to sites list
|
||||
add_filter('manage_sites-network_columns', array($this, 'add_site_id_column'), 20);
|
||||
add_action('manage_sites_custom_column', array($this, 'display_site_id_column'), 10, 2);
|
||||
add_action('admin_print_styles', array($this, 'site_id_column_style'));
|
||||
|
||||
// AJAX handlers
|
||||
add_action('wp_ajax_dm_check_domain_health', array($this, 'ajax_check_domain_health'));
|
||||
add_action('wp_ajax_dm_import_csv', array($this, 'ajax_import_csv'));
|
||||
|
||||
// Scheduled tasks
|
||||
add_action('dm_domain_health_check', array($this, 'scheduled_health_check'));
|
||||
|
||||
// Admin init actions
|
||||
add_action('admin_init', array($this, 'handle_export'));
|
||||
add_action('admin_init', array($this, 'handle_health_manual_check'));
|
||||
add_action('admin_init', array($this, 'handle_health_settings_save'));
|
||||
}
|
||||
|
||||
public function add_menu_pages() {
|
||||
add_submenu_page(
|
||||
'settings.php',
|
||||
__('Domain Health', 'wp-domain-mapping'),
|
||||
__('Domain Health', 'wp-domain-mapping'),
|
||||
'manage_network',
|
||||
'domain-mapping-health',
|
||||
'dm_render_health_page'
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'settings.php',
|
||||
__('Import/Export Domains', 'wp-domain-mapping'),
|
||||
__('Import/Export Domains', 'wp-domain-mapping'),
|
||||
'manage_network',
|
||||
'domain-mapping-import-export',
|
||||
'dm_render_import_export_page'
|
||||
);
|
||||
}
|
||||
|
||||
// Site ID Display Functions
|
||||
public function add_site_id_to_toolbar($admin_bar) {
|
||||
// Only show to admins or network admins
|
||||
if (!current_user_can('manage_options') && !is_super_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
|
||||
$admin_bar->add_menu(array(
|
||||
'id' => 'wp-site-ID',
|
||||
'title' => sprintf(__('Site ID: %d', 'wp-domain-mapping'), $blog_id),
|
||||
'href' => is_super_admin() ? esc_url(network_admin_url('site-info.php?id=' . $blog_id)) : '#',
|
||||
'meta' => array(
|
||||
'title' => is_super_admin() ? __('Edit this site', 'wp-domain-mapping') : __('Current site ID', 'wp-domain-mapping'),
|
||||
'class' => 'dm-site-id-menu'
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function add_site_id_column($columns) {
|
||||
// Add site ID column after first column
|
||||
$columns = array_slice($columns, 0, 1, true) +
|
||||
array('dm_site_id' => __('Site ID', 'wp-domain-mapping')) +
|
||||
array_slice($columns, 1, count($columns) - 1, true);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
public function display_site_id_column($column, $blog_id) {
|
||||
if ('dm_site_id' == $column) {
|
||||
echo '<span class="dm-site-id-badge">' . esc_html($blog_id) . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
public function site_id_column_style() {
|
||||
if ('sites-network' == get_current_screen()->id) {
|
||||
?>
|
||||
<style type="text/css">
|
||||
th#dm_site_id { width: 3.5em; }
|
||||
.dm-site-id-badge {
|
||||
display: inline-block;
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
// Health Check Functions
|
||||
public function schedule_health_check() {
|
||||
if (!wp_next_scheduled('dm_domain_health_check')) {
|
||||
wp_schedule_event(time(), 'daily', 'dm_domain_health_check');
|
||||
}
|
||||
}
|
||||
|
||||
public function unschedule_health_check() {
|
||||
$timestamp = wp_next_scheduled('dm_domain_health_check');
|
||||
if ($timestamp) {
|
||||
wp_unschedule_event($timestamp, 'dm_domain_health_check');
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_health_manual_check() {
|
||||
if (isset($_POST['dm_manual_health_check']) && $_POST['dm_manual_health_check']) {
|
||||
// Verify nonce
|
||||
if (!isset($_POST['dm_manual_health_check_nonce']) || !wp_verify_nonce($_POST['dm_manual_health_check_nonce'], 'dm_manual_health_check')) {
|
||||
wp_die(__('Security check failed.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to perform this action.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Run the health check
|
||||
$this->run_health_check_for_all_domains();
|
||||
|
||||
// Redirect back to health page
|
||||
wp_redirect(add_query_arg(array('page' => 'domain-mapping-health', 'checked' => 1), network_admin_url('settings.php')));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function handle_health_settings_save() {
|
||||
if (isset($_POST['dm_health_settings']) && $_POST['dm_health_settings']) {
|
||||
// Verify nonce
|
||||
if (!isset($_POST['dm_health_settings_nonce']) || !wp_verify_nonce($_POST['dm_health_settings_nonce'], 'dm_health_settings')) {
|
||||
wp_die(__('Security check failed.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to perform this action.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Save settings
|
||||
$health_check_enabled = isset($_POST['health_check_enabled']) ? (bool) $_POST['health_check_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']) : '';
|
||||
$ssl_expiry_threshold = isset($_POST['ssl_expiry_threshold']) ? intval($_POST['ssl_expiry_threshold']) : 14;
|
||||
|
||||
update_site_option('dm_health_check_enabled', $health_check_enabled);
|
||||
update_site_option('dm_health_notifications_enabled', $health_notifications_enabled);
|
||||
update_site_option('dm_notification_email', $notification_email);
|
||||
update_site_option('dm_ssl_expiry_threshold', $ssl_expiry_threshold);
|
||||
|
||||
// If auto check is enabled, ensure cron is set
|
||||
if ($health_check_enabled) {
|
||||
$this->schedule_health_check();
|
||||
} else {
|
||||
$this->unschedule_health_check();
|
||||
}
|
||||
|
||||
// Redirect back to health page
|
||||
wp_redirect(add_query_arg(array('page' => 'domain-mapping-health', 'settings-updated' => 1), network_admin_url('settings.php')));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function ajax_check_domain_health() {
|
||||
// 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_check_domain_health')) {
|
||||
wp_send_json_error(__('Security check failed.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Get domain
|
||||
$domain = isset($_POST['domain']) ? sanitize_text_field($_POST['domain']) : '';
|
||||
if (empty($domain)) {
|
||||
wp_send_json_error(__('No domain specified.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Run health check
|
||||
$result = $this->check_domain_health($domain);
|
||||
|
||||
// Save result
|
||||
$this->db->save_health_result($domain, $result);
|
||||
|
||||
// Return result
|
||||
wp_send_json_success($result);
|
||||
}
|
||||
|
||||
public function scheduled_health_check() {
|
||||
// Check if health checks are enabled
|
||||
if (!get_site_option('dm_health_check_enabled', true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->run_health_check_for_all_domains();
|
||||
}
|
||||
|
||||
private function run_health_check_for_all_domains() {
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
|
||||
// Get all domains
|
||||
$domains = $wpdb->get_col("SELECT domain FROM {$table}");
|
||||
|
||||
// Initialize issues array
|
||||
$issues = array();
|
||||
|
||||
// Check each domain
|
||||
foreach ($domains as $domain) {
|
||||
$result = $this->check_domain_health($domain);
|
||||
$this->db->save_health_result($domain, $result);
|
||||
|
||||
// Check for issues
|
||||
if ($this->has_health_issues($result)) {
|
||||
$issues[$domain] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
// Send notifications if enabled and issues exist
|
||||
if (!empty($issues) && get_site_option('dm_health_notifications_enabled', true)) {
|
||||
$this->send_health_notification($issues);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function check_domain_health($domain) {
|
||||
$result = array(
|
||||
'domain' => $domain,
|
||||
'last_check' => current_time('mysql'),
|
||||
'dns_status' => 'error',
|
||||
'dns_message' => __('DNS check not performed', 'wp-domain-mapping'),
|
||||
'resolved_ip' => '',
|
||||
'ssl_valid' => false,
|
||||
'ssl_expiry' => '',
|
||||
'accessible' => false,
|
||||
'response_code' => 0
|
||||
);
|
||||
|
||||
// Get server IP or CNAME
|
||||
$server_ip = get_site_option('dm_ipaddress', '');
|
||||
$server_cname = get_site_option('dm_cname', '');
|
||||
|
||||
// Check DNS setting
|
||||
$domain_ip = gethostbyname($domain);
|
||||
$result['resolved_ip'] = $domain_ip;
|
||||
|
||||
if ($domain_ip && $domain_ip !== $domain) {
|
||||
if ($server_ip && strpos($server_ip, $domain_ip) !== false) {
|
||||
$result['dns_status'] = 'success';
|
||||
$result['dns_message'] = __('Domain A record is correctly pointing to server IP.', 'wp-domain-mapping');
|
||||
} elseif ($server_cname && function_exists('dns_get_record')) {
|
||||
$dns_records = @dns_get_record($domain, DNS_CNAME);
|
||||
$has_valid_cname = false;
|
||||
|
||||
if ($dns_records) {
|
||||
foreach ($dns_records as $record) {
|
||||
if (isset($record['target']) &&
|
||||
(
|
||||
$record['target'] === $server_cname ||
|
||||
strpos($record['target'], $server_cname) !== false
|
||||
)) {
|
||||
$has_valid_cname = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_valid_cname) {
|
||||
$result['dns_status'] = 'success';
|
||||
$result['dns_message'] = __('Domain CNAME record is correctly configured.', 'wp-domain-mapping');
|
||||
} else {
|
||||
$result['dns_message'] = __('Domain is not pointing to the correct server.', 'wp-domain-mapping');
|
||||
}
|
||||
} else {
|
||||
$result['dns_message'] = __('Cannot verify DNS configuration.', 'wp-domain-mapping');
|
||||
}
|
||||
} else {
|
||||
$result['dns_message'] = __('Domain does not resolve to an IP address.', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// Check site accessibility and SSL
|
||||
$response = $this->test_domain_connection($domain);
|
||||
|
||||
if ($response) {
|
||||
$result['accessible'] = $response['accessible'];
|
||||
$result['response_code'] = $response['response_code'];
|
||||
$result['ssl_valid'] = $response['ssl_valid'];
|
||||
$result['ssl_expiry'] = $response['ssl_expiry'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function test_domain_connection($domain) {
|
||||
if (!function_exists('curl_init')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'accessible' => false,
|
||||
'response_code' => 0,
|
||||
'ssl_valid' => false,
|
||||
'ssl_expiry' => ''
|
||||
);
|
||||
|
||||
// Test HTTPS connection
|
||||
$ch = curl_init('https://' . $domain);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_setopt($ch, CURLOPT_CERTINFO, true);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$result['response_code'] = $response_code;
|
||||
|
||||
if ($response !== false && $response_code > 0) {
|
||||
$result['accessible'] = ($response_code >= 200 && $response_code < 400);
|
||||
$result['ssl_valid'] = ($response !== false);
|
||||
|
||||
// Get SSL certificate info
|
||||
$cert_info = curl_getinfo($ch, CURLINFO_CERTINFO);
|
||||
if (!empty($cert_info) && isset($cert_info[0]['Expire date'])) {
|
||||
$result['ssl_expiry'] = $cert_info[0]['Expire date'];
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// If HTTPS failed, try HTTP
|
||||
if (!$result['accessible']) {
|
||||
$ch = curl_init('http://' . $domain);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
if ($response !== false && $response_code > 0) {
|
||||
$result['accessible'] = ($response_code >= 200 && $response_code < 400);
|
||||
$result['response_code'] = $response_code;
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function has_health_issues($result) {
|
||||
// Check DNS issues
|
||||
if ($result['dns_status'] !== 'success') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check SSL issues
|
||||
if (!$result['ssl_valid']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check SSL expiry
|
||||
if (!empty($result['ssl_expiry'])) {
|
||||
$expiry_date = strtotime($result['ssl_expiry']);
|
||||
$threshold = get_site_option('dm_ssl_expiry_threshold', 14);
|
||||
$threshold_date = strtotime('+' . $threshold . ' days');
|
||||
|
||||
if ($expiry_date <= $threshold_date) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check accessibility issues
|
||||
if (!$result['accessible']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function send_health_notification($issues) {
|
||||
$notification_email = get_site_option('dm_notification_email', get_option('admin_email'));
|
||||
|
||||
if (empty($notification_email)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$site_name = get_bloginfo('name');
|
||||
$subject = sprintf(__('[%s] Domain Mapping Health Alert', 'wp-domain-mapping'), $site_name);
|
||||
|
||||
// Build email content
|
||||
$message = sprintf(__('Domain health issues were detected on %s.', 'wp-domain-mapping'), $site_name) . "\n\n";
|
||||
$message .= __('The following domains have issues:', 'wp-domain-mapping') . "\n\n";
|
||||
|
||||
foreach ($issues as $domain => $result) {
|
||||
$message .= sprintf(__('Domain: %s', 'wp-domain-mapping'), $domain) . "\n";
|
||||
|
||||
// Add DNS status
|
||||
if ($result['dns_status'] !== 'success') {
|
||||
$message .= " - " . sprintf(__('DNS Issue: %s', 'wp-domain-mapping'), $result['dns_message']) . "\n";
|
||||
}
|
||||
|
||||
// Add SSL status
|
||||
if (!$result['ssl_valid']) {
|
||||
$message .= " - " . __('SSL Certificate is invalid or missing.', 'wp-domain-mapping') . "\n";
|
||||
} elseif (!empty($result['ssl_expiry'])) {
|
||||
$expiry_date = strtotime($result['ssl_expiry']);
|
||||
$threshold = get_site_option('dm_ssl_expiry_threshold', 14);
|
||||
$threshold_date = strtotime('+' . $threshold . ' days');
|
||||
|
||||
if ($expiry_date <= $threshold_date) {
|
||||
$message .= " - " . sprintf(
|
||||
__('SSL Certificate expires on %s (within %d days).', 'wp-domain-mapping'),
|
||||
date('Y-m-d', $expiry_date),
|
||||
$threshold
|
||||
) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Add accessibility status
|
||||
if (!$result['accessible']) {
|
||||
$message .= " - " . __('Site is not accessible.', 'wp-domain-mapping') . "\n";
|
||||
if ($result['response_code'] > 0) {
|
||||
$message .= " " . sprintf(__('HTTP Response Code: %d', 'wp-domain-mapping'), $result['response_code']) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$message .= "\n";
|
||||
}
|
||||
|
||||
// Add resolution link
|
||||
$message .= sprintf(
|
||||
__('To view and manage these issues, please visit: %s', 'wp-domain-mapping'),
|
||||
network_admin_url('settings.php?page=domain-mapping-health')
|
||||
) . "\n";
|
||||
|
||||
// Send email
|
||||
wp_mail($notification_email, $subject, $message);
|
||||
}
|
||||
|
||||
// Import/Export Functions
|
||||
public function handle_export() {
|
||||
if (!isset($_POST['domain_mapping_export']) || !$_POST['domain_mapping_export']) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_die(__('You do not have sufficient permissions to export data.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Verify nonce
|
||||
if (!isset($_POST['domain_mapping_export_nonce']) || !wp_verify_nonce($_POST['domain_mapping_export_nonce'], 'domain_mapping_export')) {
|
||||
wp_die(__('Invalid security token. Please try again.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Get options
|
||||
$include_header = isset($_POST['include_header']) ? (bool) $_POST['include_header'] : false;
|
||||
$blog_id_filter = isset($_POST['blog_id_filter']) && !empty($_POST['blog_id_filter']) ? intval($_POST['blog_id_filter']) : 0;
|
||||
|
||||
// Get domain mapping data
|
||||
global $wpdb;
|
||||
$table = $wpdb->base_prefix . WP_DOMAIN_MAPPING_TABLE_DOMAINS;
|
||||
$sql = "SELECT blog_id, domain, active FROM {$table}";
|
||||
|
||||
if ($blog_id_filter > 0) {
|
||||
$sql .= $wpdb->prepare(" WHERE blog_id = %d", $blog_id_filter);
|
||||
}
|
||||
|
||||
$domains = $wpdb->get_results($sql, ARRAY_A);
|
||||
|
||||
if (empty($domains)) {
|
||||
// No data
|
||||
wp_redirect(add_query_arg(array('page' => 'domain-mapping-import-export', 'export' => 'empty'), network_admin_url('settings.php')));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Set up CSV output
|
||||
$filename = 'domain-mappings-' . date('Y-m-d') . '.csv';
|
||||
|
||||
header('Content-Type: text/csv; charset=utf-8');
|
||||
header('Content-Disposition: attachment; filename=' . $filename);
|
||||
|
||||
$output = fopen('php://output', 'w');
|
||||
|
||||
// Add header row
|
||||
if ($include_header) {
|
||||
fputcsv($output, array('blog_id', 'domain', 'active'));
|
||||
}
|
||||
|
||||
// Add data rows
|
||||
foreach ($domains as $domain) {
|
||||
fputcsv($output, $domain);
|
||||
}
|
||||
|
||||
fclose($output);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function ajax_import_csv() {
|
||||
// Check permissions
|
||||
if (!current_user_can('manage_network')) {
|
||||
wp_send_json_error(__('You do not have sufficient permissions to import data.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Verify nonce
|
||||
if (!isset($_POST['domain_mapping_import_nonce']) || !wp_verify_nonce($_POST['domain_mapping_import_nonce'], 'domain_mapping_import')) {
|
||||
wp_send_json_error(__('Invalid security token. Please try again.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Check file
|
||||
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'));
|
||||
}
|
||||
|
||||
// Get options
|
||||
$has_header = isset($_POST['has_header']) ? (bool) $_POST['has_header'] : false;
|
||||
$update_existing = isset($_POST['update_existing']) ? (bool) $_POST['update_existing'] : false;
|
||||
$validate_sites = isset($_POST['validate_sites']) ? (bool) $_POST['validate_sites'] : true;
|
||||
|
||||
// Open file
|
||||
$file = fopen($_FILES['csv_file']['tmp_name'], 'r');
|
||||
if (!$file) {
|
||||
wp_send_json_error(__('Could not open the uploaded file.', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
// Initialize counters and log
|
||||
$imported = 0;
|
||||
$skipped = 0;
|
||||
$errors = 0;
|
||||
$log = array();
|
||||
|
||||
// Skip header row
|
||||
if ($has_header) {
|
||||
fgetcsv($file);
|
||||
}
|
||||
|
||||
// Process each row
|
||||
$row_num = $has_header ? 2 : 1; // Account for header row
|
||||
|
||||
while (($data = fgetcsv($file)) !== false) {
|
||||
// Check data format
|
||||
if (count($data) < 3) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Invalid format. Expected at least 3 columns.', 'wp-domain-mapping'), $row_num)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse data
|
||||
$blog_id = intval($data[0]);
|
||||
$domain = $this->core->clean_domain(trim($data[1]));
|
||||
$active = intval($data[2]);
|
||||
|
||||
// Validate blog_id
|
||||
if ($blog_id <= 0) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Invalid blog ID: %d', 'wp-domain-mapping'), $row_num, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate site exists
|
||||
if ($validate_sites && !get_blog_details($blog_id)) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Site ID %d does not exist.', 'wp-domain-mapping'), $row_num, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate domain format
|
||||
if (!$this->core->validate_domain($domain)) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Invalid domain format: %s', 'wp-domain-mapping'), $row_num, $domain)
|
||||
);
|
||||
$errors++;
|
||||
$row_num++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if domain already exists
|
||||
$existing = $this->db->get_domain_by_name($domain);
|
||||
|
||||
if ($existing) {
|
||||
if ($existing->blog_id != $blog_id) {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Domain %s is already mapped to blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $existing->blog_id)
|
||||
);
|
||||
$errors++;
|
||||
} elseif (!$update_existing) {
|
||||
$log[] = array(
|
||||
'status' => 'warning',
|
||||
'message' => sprintf(__('Row %d: Domain %s already exists for blog ID %d. Skipped.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$skipped++;
|
||||
} else {
|
||||
// Update existing domain
|
||||
$success = $this->db->update_domain($domain, $blog_id, $active);
|
||||
|
||||
if ($success) {
|
||||
$log[] = array(
|
||||
'status' => 'success',
|
||||
'message' => sprintf(__('Row %d: Updated domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$imported++;
|
||||
} else {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Failed to update domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add new domain
|
||||
$success = $this->db->add_domain($blog_id, $domain, $active);
|
||||
|
||||
if ($success) {
|
||||
$log[] = array(
|
||||
'status' => 'success',
|
||||
'message' => sprintf(__('Row %d: Added domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$imported++;
|
||||
} else {
|
||||
$log[] = array(
|
||||
'status' => 'error',
|
||||
'message' => sprintf(__('Row %d: Failed to add domain %s for blog ID %d.', 'wp-domain-mapping'),
|
||||
$row_num, $domain, $blog_id)
|
||||
);
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
|
||||
$row_num++;
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
|
||||
// Build response
|
||||
$message = sprintf(
|
||||
__('Import completed: %d imported, %d skipped, %d errors.', 'wp-domain-mapping'),
|
||||
$imported, $skipped, $errors
|
||||
);
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => $message,
|
||||
'imported' => $imported,
|
||||
'skipped' => $skipped,
|
||||
'errors' => $errors,
|
||||
'details' => $log
|
||||
));
|
||||
}
|
||||
}
|
96
sunrise.php
96
sunrise.php
|
@ -1,53 +1,61 @@
|
|||
<?php
|
||||
/**
|
||||
* Sunrise script for WP Domain Mapping plugin
|
||||
* Sunrise.php for WordPress Domain Mapping
|
||||
*
|
||||
* This file enables domain mapping functionality for WordPress multisite networks by
|
||||
* overriding the default blog routing based on custom domains stored in the database.
|
||||
* It must be placed in wp-content/sunrise.php and activated via define('SUNRISE', 'on')
|
||||
* in wp-config.php.
|
||||
*
|
||||
* @package WP Domain Mapping
|
||||
* @author WPDomain.com
|
||||
* @link https://wpdomain.com/plugins/wp-domain-mapping/
|
||||
* @version 1.3.3
|
||||
* @license GPL v2 or later
|
||||
* @license URI https://www.gnu.org/licenses/gpl-2.0.html
|
||||
* This file must be copied to wp-content/sunrise.php
|
||||
* Also, you must add "define('SUNRISE', 'on');" to wp-config.php
|
||||
* Make sure the SUNRISE definition appears before the last require_once in wp-config.php
|
||||
*/
|
||||
|
||||
if ( !defined( 'SUNRISE_LOADED' ) )
|
||||
define( 'SUNRISE_LOADED', 1 );
|
||||
|
||||
if ( defined( 'COOKIE_DOMAIN' ) ) {
|
||||
die( 'The constant "COOKIE_DOMAIN" is defined (probably in wp-config.php). Please remove or comment out that define() line.' );
|
||||
// Mark as loaded
|
||||
define('SUNRISE_LOADED', true);
|
||||
|
||||
// Check if we're in WP multi-site mode
|
||||
if (!defined('MULTISITE') || !MULTISITE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wpdb->dmtable = $wpdb->base_prefix . 'domain_mapping';
|
||||
$dm_domain = $_SERVER[ 'HTTP_HOST' ];
|
||||
// Enable domain mapping
|
||||
define('DOMAIN_MAPPING', 1);
|
||||
|
||||
if( ( $nowww = preg_replace( '|^www\.|', '', $dm_domain ) ) != $dm_domain )
|
||||
$where = $wpdb->prepare( 'domain IN (%s,%s)', $dm_domain, $nowww );
|
||||
else
|
||||
$where = $wpdb->prepare( 'domain = %s', $dm_domain );
|
||||
|
||||
$wpdb->suppress_errors();
|
||||
$domain_mapping_id = $wpdb->get_var( "SELECT blog_id FROM {$wpdb->dmtable} WHERE {$where} ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1" );
|
||||
$wpdb->suppress_errors( false );
|
||||
if( $domain_mapping_id ) {
|
||||
$current_blog = $wpdb->get_row("SELECT * FROM {$wpdb->blogs} WHERE blog_id = '$domain_mapping_id' LIMIT 1");
|
||||
$current_blog->domain = $dm_domain;
|
||||
$current_blog->path = '/';
|
||||
$blog_id = $domain_mapping_id;
|
||||
$site_id = $current_blog->site_id;
|
||||
|
||||
define( 'COOKIE_DOMAIN', $dm_domain );
|
||||
|
||||
$current_site = $wpdb->get_row( "SELECT * from {$wpdb->site} WHERE id = '{$current_blog->site_id}' LIMIT 0,1" );
|
||||
$current_site->blog_id = $wpdb->get_var( "SELECT blog_id FROM {$wpdb->blogs} WHERE domain='{$current_site->domain}' AND path='{$current_site->path}'" );
|
||||
if ( function_exists( 'get_site_option' ) )
|
||||
$current_site->site_name = get_site_option( 'site_name' );
|
||||
elseif ( function_exists( 'get_current_site_name' ) )
|
||||
$current_site = get_current_site_name( $current_site );
|
||||
|
||||
define( 'DOMAIN_MAPPING', 1 );
|
||||
// Check if we're on the main site already
|
||||
if (defined('COOKIE_DOMAIN') && COOKIE_DOMAIN == $_SERVER['HTTP_HOST']) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb, $current_blog, $current_site;
|
||||
|
||||
// Get domains table name
|
||||
$domain_mapping_table = $wpdb->base_prefix . 'domain_mapping';
|
||||
|
||||
// Check for the current domain in the domain mapping table
|
||||
$domain = $wpdb->escape($_SERVER['HTTP_HOST']);
|
||||
$blog_id = $wpdb->get_var("SELECT blog_id FROM {$domain_mapping_table} WHERE domain = '{$domain}' LIMIT 1");
|
||||
|
||||
// If we found a mapped domain, override current_blog
|
||||
if (!empty($blog_id)) {
|
||||
// Get the mapped blog details
|
||||
$mapped_blog = $wpdb->get_row("SELECT * FROM {$wpdb->blogs} WHERE blog_id = '{$blog_id}' LIMIT 1");
|
||||
|
||||
if ($mapped_blog) {
|
||||
// Override current_blog
|
||||
$current_blog = $mapped_blog;
|
||||
|
||||
// Also set the cookie domain to the current domain
|
||||
define('COOKIE_DOMAIN', $_SERVER['HTTP_HOST']);
|
||||
|
||||
// Define the mapped domain constant
|
||||
define('MAPPED_DOMAIN', true);
|
||||
|
||||
// Allow other plugins to know this is a mapped domain
|
||||
$GLOBALS['dm_domain'] = array(
|
||||
'original' => $current_blog->domain,
|
||||
'mapped' => $_SERVER['HTTP_HOST']
|
||||
);
|
||||
|
||||
// Fix request URI for path sites
|
||||
if ($current_blog->path != '/' && ($current_blog->path != '/wp/' || strpos($_SERVER['REQUEST_URI'], '/wp/') === false)) {
|
||||
$current_blog->path = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue