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
a1869ff494
commit
dd5e4f04a0
12 changed files with 3705 additions and 2138 deletions
343
admin/pages.php
343
admin/pages.php
|
@ -36,6 +36,7 @@ function dm_render_admin_page() {
|
|||
$current_tab = isset( $_GET['tab'] ) ? sanitize_text_field( $_GET['tab'] ) : 'settings';
|
||||
$tabs = array(
|
||||
'settings' => __( 'Settings', 'wp-domain-mapping' ),
|
||||
'dns-setup' => __( 'DNS Setup', 'wp-domain-mapping' ),
|
||||
'health' => __( 'Domain Health', 'wp-domain-mapping' ),
|
||||
'import-export' => __( 'Import/Export', 'wp-domain-mapping' )
|
||||
);
|
||||
|
@ -81,7 +82,9 @@ function dm_render_admin_page() {
|
|||
}
|
||||
?>
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
<!-- Main Configuration Card -->
|
||||
<div class="card domain-mapping-card">
|
||||
<!-- Tab Navigation inside card -->
|
||||
<div class="domain-mapping-tabs">
|
||||
<?php foreach ( $tabs as $tab_key => $tab_label ) : ?>
|
||||
<button type="button" class="domain-mapping-tab <?php echo $current_tab === $tab_key ? 'active' : ''; ?>"
|
||||
|
@ -99,7 +102,16 @@ function dm_render_admin_page() {
|
|||
<?php dm_render_settings_content(); ?>
|
||||
</div>
|
||||
|
||||
<!-- Health Tab -->
|
||||
<!-- DNS Setup Tab -->
|
||||
<div class="domain-mapping-section" data-section="dns-setup" <?php echo $current_tab !== 'dns-setup' ? 'style="display:none;"' : ''; ?>>
|
||||
<?php
|
||||
$dm_ipaddress = get_site_option( 'dm_ipaddress', '' );
|
||||
$dm_cname = get_site_option( 'dm_cname', '' );
|
||||
dm_render_dns_content( $dm_ipaddress, $dm_cname );
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Domain Health Tab -->
|
||||
<div class="domain-mapping-section" data-section="health" <?php echo $current_tab !== 'health' ? 'style="display:none;"' : ''; ?>>
|
||||
<?php dm_render_health_content(); ?>
|
||||
</div>
|
||||
|
@ -111,6 +123,10 @@ function dm_render_admin_page() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Installation Check Card (independent) -->
|
||||
<?php dm_render_installation_check(); ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function switchTab(tab) {
|
||||
// Update URL without reloading
|
||||
|
@ -131,7 +147,7 @@ function dm_render_admin_page() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render settings tab content
|
||||
* Render settings tab content (without card wrapper)
|
||||
*/
|
||||
function dm_render_settings_content() {
|
||||
// Get current options
|
||||
|
@ -154,7 +170,6 @@ function dm_render_settings_content() {
|
|||
}
|
||||
}
|
||||
?>
|
||||
<div class="card domain-mapping-card">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="update" />
|
||||
<?php wp_nonce_field( 'domain_mapping' ); ?>
|
||||
|
@ -275,16 +290,123 @@ function dm_render_settings_content() {
|
|||
</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- DNS Instructions and Installation Check sections from settings-page.php -->
|
||||
<?php dm_render_dns_instructions( $dm_ipaddress, $dm_cname ); ?>
|
||||
<?php dm_render_installation_check(); ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render DNS instructions
|
||||
* Render DNS setup tab content (without card wrapper)
|
||||
*/
|
||||
function dm_render_dns_content( $dm_ipaddress, $dm_cname ) {
|
||||
?>
|
||||
<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>
|
||||
<th><?php esc_html_e( 'TTL', '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>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>CNAME</code></td>
|
||||
<td><code>www</code></td>
|
||||
<td><code><?php echo esc_html( $dm_cname ); ?></code></td>
|
||||
<td><code>3600</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>
|
||||
<th><?php esc_html_e( 'TTL', '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>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<tr>
|
||||
<td><code>A</code></td>
|
||||
<td><code>www</code></td>
|
||||
<td><code><?php echo esc_html( $ips[0] ); ?></code></td>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
</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 in the Settings tab 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>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render DNS instructions (independent card) - kept for backward compatibility
|
||||
*/
|
||||
function dm_render_dns_instructions( $dm_ipaddress, $dm_cname ) {
|
||||
?>
|
||||
|
@ -311,6 +433,7 @@ function dm_render_dns_instructions( $dm_ipaddress, $dm_cname ) {
|
|||
<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>
|
||||
<th><?php esc_html_e( 'TTL', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -318,6 +441,13 @@ function dm_render_dns_instructions( $dm_ipaddress, $dm_cname ) {
|
|||
<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>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>CNAME</code></td>
|
||||
<td><code>www</code></td>
|
||||
<td><code><?php echo esc_html( $dm_cname ); ?></code></td>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -343,6 +473,7 @@ function dm_render_dns_instructions( $dm_ipaddress, $dm_cname ) {
|
|||
<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>
|
||||
<th><?php esc_html_e( 'TTL', 'wp-domain-mapping' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -354,8 +485,15 @@ function dm_render_dns_instructions( $dm_ipaddress, $dm_cname ) {
|
|||
<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>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<tr>
|
||||
<td><code>A</code></td>
|
||||
<td><code>www</code></td>
|
||||
<td><code><?php echo esc_html( $ips[0] ); ?></code></td>
|
||||
<td><code>3600</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -382,7 +520,7 @@ function dm_render_dns_instructions( $dm_ipaddress, $dm_cname ) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render installation check
|
||||
* Render installation check (independent card)
|
||||
*/
|
||||
function dm_render_installation_check() {
|
||||
?>
|
||||
|
@ -467,24 +605,44 @@ function dm_render_installation_check() {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( ! defined( 'COOKIE_DOMAIN' ) ) : ?>
|
||||
<?php
|
||||
// Check COOKIE_DOMAIN configuration in a performance-friendly way
|
||||
$cookie_domain_status = dm_check_cookie_domain_status();
|
||||
|
||||
if ($cookie_domain_status['is_optimal']): ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php elseif ($cookie_domain_status['has_warning']): ?>
|
||||
<span class="dashicons dashicons-warning" style="color: #f56e28;"></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 if ($cookie_domain_status['is_optimal']): ?>
|
||||
<span style="color: #46b450;">
|
||||
<?php echo esc_html($cookie_domain_status['message']); ?>
|
||||
</span>
|
||||
<?php elseif ($cookie_domain_status['has_warning']): ?>
|
||||
<span style="color: #f56e28;">
|
||||
<?php echo esc_html($cookie_domain_status['message']); ?>
|
||||
</span>
|
||||
<br><small style="color: #666;">
|
||||
<?php esc_html_e('This may cause login issues on mapped domains. Consider removing the COOKIE_DOMAIN definition from wp-config.php.', 'wp-domain-mapping'); ?>
|
||||
</small>
|
||||
<?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>'
|
||||
);
|
||||
?>
|
||||
<span style="color: #dc3232;">
|
||||
<?php echo esc_html($cookie_domain_status['message']); ?>
|
||||
</span>
|
||||
<br><small style="color: #666;">
|
||||
<?php esc_html_e('Remove the define(\'COOKIE_DOMAIN\', ...) line from wp-config.php to enable dynamic cookie domain handling.', 'wp-domain-mapping'); ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (defined('WP_DEBUG') && WP_DEBUG && !empty($cookie_domain_status['debug_info'])): ?>
|
||||
<br><small style="color: #999; font-style: italic;">
|
||||
<?php echo esc_html($cookie_domain_status['debug_info']); ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -560,7 +718,6 @@ function dm_render_health_content() {
|
|||
$health_check_progress = get_site_option( 'dm_health_check_progress', false );
|
||||
?>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e( 'Domain Health Status', 'wp-domain-mapping' ); ?></h2>
|
||||
|
||||
<?php if ( $health_check_progress !== false ) : ?>
|
||||
|
@ -733,10 +890,8 @@ function dm_render_health_content() {
|
|||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card">
|
||||
<h2><?php _e( 'Health Check Settings', 'wp-domain-mapping' ); ?></h2>
|
||||
<h3><?php _e( 'Health Check Settings', 'wp-domain-mapping' ); ?></h3>
|
||||
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field( 'dm_health_settings', 'dm_health_settings_nonce' ); ?>
|
||||
|
@ -796,7 +951,6 @@ function dm_render_health_content() {
|
|||
<input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Save Changes', 'wp-domain-mapping' ); ?>">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
|
@ -891,8 +1045,8 @@ function dm_render_import_export_content() {
|
|||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card domain-mapping-card" <?php echo ! $wp_china_yes_active ? 'style="opacity: 0.5; pointer-events: none;"' : ''; ?>>
|
||||
<h2><?php _e( 'Export Domain Mappings', 'wp-domain-mapping' ); ?></h2>
|
||||
<div class="export-section" <?php echo ! $wp_china_yes_active ? 'style="opacity: 0.5; pointer-events: none;"' : ''; ?>>
|
||||
<p><?php _e( 'Export all domain mappings to a CSV file.', 'wp-domain-mapping' ); ?></p>
|
||||
|
||||
<form method="post" action="">
|
||||
|
@ -918,8 +1072,8 @@ function dm_render_import_export_content() {
|
|||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card domain-mapping-card" <?php echo ! $wp_china_yes_active ? 'style="opacity: 0.5; pointer-events: none;"' : ''; ?>>
|
||||
<h2><?php _e( 'Import Domain Mappings', 'wp-domain-mapping' ); ?></h2>
|
||||
<div class="import-section" <?php echo ! $wp_china_yes_active ? 'style="opacity: 0.5; pointer-events: none;"' : ''; ?>>
|
||||
<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">
|
||||
|
@ -978,7 +1132,6 @@ function dm_render_import_export_content() {
|
|||
</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>
|
||||
|
||||
|
@ -1009,7 +1162,6 @@ function dm_render_import_export_content() {
|
|||
<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>
|
||||
|
||||
<?php if ( $wp_china_yes_active ) : ?>
|
||||
<script type="text/javascript">
|
||||
|
@ -1150,3 +1302,134 @@ function dm_render_user_page( $protocol = null, $domains = null ) {
|
|||
// Include original user page content
|
||||
require_once WP_DOMAIN_MAPPING_DIR_PATH . 'admin/user-page.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check COOKIE_DOMAIN configuration status in a performance-friendly way
|
||||
* Uses caching to avoid reading wp-config.php on every page load
|
||||
*
|
||||
* @return array Status information about COOKIE_DOMAIN configuration
|
||||
*/
|
||||
function dm_check_cookie_domain_status() {
|
||||
// Cache key for storing the check result
|
||||
$cache_key = 'dm_cookie_domain_check_' . md5(ABSPATH);
|
||||
$cached_result = get_transient($cache_key);
|
||||
|
||||
// Return cached result if still valid (cached for 1 hour)
|
||||
if ($cached_result !== false) {
|
||||
// Always check runtime values as they can change
|
||||
$cached_result['runtime_defined'] = defined('COOKIE_DOMAIN');
|
||||
$cached_result['is_mapped_request'] = defined('MAPPED_DOMAIN') && MAPPED_DOMAIN;
|
||||
|
||||
// Update debug info
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
$debug_parts = array();
|
||||
$debug_parts[] = 'Runtime defined: ' . ($cached_result['runtime_defined'] ? 'Yes' : 'No');
|
||||
if ($cached_result['runtime_defined']) {
|
||||
$debug_parts[] = 'Value: ' . COOKIE_DOMAIN;
|
||||
}
|
||||
$debug_parts[] = 'Mapped request: ' . ($cached_result['is_mapped_request'] ? 'Yes' : 'No');
|
||||
$cached_result['debug_info'] = 'Debug: ' . implode(', ', $debug_parts);
|
||||
}
|
||||
|
||||
return $cached_result;
|
||||
}
|
||||
|
||||
// Initialize result array
|
||||
$result = array(
|
||||
'is_optimal' => false,
|
||||
'has_warning' => false,
|
||||
'message' => '',
|
||||
'debug_info' => '',
|
||||
'wp_config_has_definition' => false,
|
||||
'runtime_defined' => defined('COOKIE_DOMAIN'),
|
||||
'is_mapped_request' => defined('MAPPED_DOMAIN') && MAPPED_DOMAIN
|
||||
);
|
||||
|
||||
// Check if COOKIE_DOMAIN is defined in wp-config.php
|
||||
$wp_config_path = ABSPATH . 'wp-config.php';
|
||||
if (file_exists($wp_config_path)) {
|
||||
// Use a more efficient approach - only read first part of file
|
||||
$file_handle = fopen($wp_config_path, 'r');
|
||||
if ($file_handle) {
|
||||
$line_count = 0;
|
||||
$max_lines = 200; // Only check first 200 lines for performance
|
||||
|
||||
while (($line = fgets($file_handle)) !== false && $line_count < $max_lines) {
|
||||
$line = trim($line);
|
||||
$line_count++;
|
||||
|
||||
// Skip empty lines and comments
|
||||
if (empty($line) || substr($line, 0, 2) === '//' || substr($line, 0, 1) === '#' || substr($line, 0, 2) === '/*') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Stop at the end of configuration section
|
||||
if (strpos($line, "require_once") !== false && strpos($line, "wp-settings.php") !== false) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for COOKIE_DOMAIN definition
|
||||
if (preg_match('/define\s*\(\s*[\'"]COOKIE_DOMAIN[\'"]/', $line)) {
|
||||
$result['wp_config_has_definition'] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose($file_handle);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine status and message - Always allow access, just show warnings
|
||||
if (!$result['wp_config_has_definition']) {
|
||||
$result['is_optimal'] = true;
|
||||
if ($result['runtime_defined'] && $result['is_mapped_request']) {
|
||||
$result['message'] = __('Not defined in wp-config.php (optimal). Currently managed by domain mapping.', 'wp-domain-mapping');
|
||||
} else {
|
||||
$result['message'] = __('Not defined in wp-config.php (optimal for domain mapping)', 'wp-domain-mapping');
|
||||
}
|
||||
} else {
|
||||
// Even if defined in wp-config.php, don't block access - just show warning
|
||||
if ($result['runtime_defined']) {
|
||||
$result['has_warning'] = true;
|
||||
$result['message'] = __('Defined in wp-config.php but currently working', 'wp-domain-mapping');
|
||||
} else {
|
||||
$result['has_warning'] = true;
|
||||
$result['message'] = __('Defined in wp-config.php (may affect some domain mapping features)', 'wp-domain-mapping');
|
||||
}
|
||||
}
|
||||
|
||||
// Add debug information if WP_DEBUG is enabled
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
$debug_parts = array();
|
||||
$debug_parts[] = 'Runtime defined: ' . ($result['runtime_defined'] ? 'Yes' : 'No');
|
||||
if ($result['runtime_defined']) {
|
||||
$debug_parts[] = 'Value: ' . COOKIE_DOMAIN;
|
||||
}
|
||||
$debug_parts[] = 'Mapped request: ' . ($result['is_mapped_request'] ? 'Yes' : 'No');
|
||||
$debug_parts[] = 'Config file check: ' . ($result['wp_config_has_definition'] ? 'Found' : 'Not found');
|
||||
$result['debug_info'] = 'Debug: ' . implode(', ', $debug_parts);
|
||||
}
|
||||
|
||||
// Cache the result for 1 hour (exclude runtime values from cache)
|
||||
$cache_data = $result;
|
||||
unset($cache_data['runtime_defined'], $cache_data['is_mapped_request'], $cache_data['debug_info']);
|
||||
set_transient($cache_key, $cache_data, HOUR_IN_SECONDS);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy function to prevent blocking access - always returns false
|
||||
* This ensures backward compatibility with any existing checks
|
||||
*/
|
||||
function dm_cookie_domain_is_blocking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe check for COOKIE_DOMAIN without blocking access
|
||||
* This can be used throughout the plugin without causing access issues
|
||||
*/
|
||||
function dm_is_cookie_domain_safe() {
|
||||
$status = dm_check_cookie_domain_status();
|
||||
return $status['is_optimal'] || $status['has_warning'];
|
||||
}
|
||||
|
|
|
@ -358,24 +358,44 @@ settings_errors( 'dm_settings' );
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ( ! defined( 'COOKIE_DOMAIN' ) ) : ?>
|
||||
<?php
|
||||
// Use the improved COOKIE_DOMAIN check function from pages.php
|
||||
$cookie_domain_status = dm_check_cookie_domain_status();
|
||||
|
||||
if ($cookie_domain_status['is_optimal']): ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
|
||||
<?php elseif ($cookie_domain_status['has_warning']): ?>
|
||||
<span class="dashicons dashicons-warning" style="color: #f56e28;"></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 if ($cookie_domain_status['is_optimal']): ?>
|
||||
<span style="color: #46b450;">
|
||||
<?php echo esc_html($cookie_domain_status['message']); ?>
|
||||
</span>
|
||||
<?php elseif ($cookie_domain_status['has_warning']): ?>
|
||||
<span style="color: #f56e28;">
|
||||
<?php echo esc_html($cookie_domain_status['message']); ?>
|
||||
</span>
|
||||
<br><small style="color: #666;">
|
||||
<?php esc_html_e('This may cause login issues on mapped domains. Consider removing the COOKIE_DOMAIN definition from wp-config.php.', 'wp-domain-mapping'); ?>
|
||||
</small>
|
||||
<?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>'
|
||||
);
|
||||
?>
|
||||
<span style="color: #dc3232;">
|
||||
<?php echo esc_html($cookie_domain_status['message']); ?>
|
||||
</span>
|
||||
<br><small style="color: #666;">
|
||||
<?php esc_html_e('Remove the define(\'COOKIE_DOMAIN\', ...) line from wp-config.php to enable dynamic cookie domain handling.', 'wp-domain-mapping'); ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (defined('WP_DEBUG') && WP_DEBUG && !empty($cookie_domain_status['debug_info'])): ?>
|
||||
<br><small style="color: #999; font-style: italic;">
|
||||
<?php echo esc_html($cookie_domain_status['debug_info']); ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* WP Domain Mapping Admin Styles */
|
||||
/* WP Domain Mapping Admin Styles - Optimized Layout */
|
||||
|
||||
/* Main cards */
|
||||
.domain-mapping-card {
|
||||
|
@ -9,9 +9,14 @@
|
|||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Tabs - Now inside the main card */
|
||||
.domain-mapping-wrapper {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.domain-mapping-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -40,8 +45,21 @@
|
|||
border-bottom-color: #dcdcde;
|
||||
}
|
||||
|
||||
/* Tab Content */
|
||||
.domain-mapping-content {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.domain-mapping-content h2:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.domain-mapping-content h3 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 15px;
|
||||
color: #1d2327;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* Search form */
|
||||
|
@ -50,7 +68,11 @@
|
|||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 20px;
|
||||
padding: 20px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.search-form-field {
|
||||
|
@ -62,6 +84,7 @@
|
|||
.search-form-field label {
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.search-form-submit {
|
||||
|
@ -72,9 +95,10 @@
|
|||
|
||||
/* Tables */
|
||||
.tablenav {
|
||||
margin: 10px 0;
|
||||
margin: 15px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tablenav-pages {
|
||||
|
@ -92,23 +116,32 @@
|
|||
font-weight: 400;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.tablenav-pages span.current {
|
||||
background: #007cba;
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
border-color: #2271b1;
|
||||
}
|
||||
|
||||
.tablenav-pages a:hover {
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
border-color: #007cba;
|
||||
}
|
||||
|
||||
.displaying-num {
|
||||
margin-left: 10px;
|
||||
color: #555;
|
||||
color: #646970;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.domains-table th,
|
||||
.logs-table th,
|
||||
.domains-health-table th {
|
||||
font-weight: 600;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.column-site-id {
|
||||
|
@ -152,8 +185,8 @@
|
|||
background: #2271b1;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
@ -161,6 +194,8 @@
|
|||
.form-table th {
|
||||
width: 200px;
|
||||
padding: 15px 10px 15px 0;
|
||||
font-weight: 600;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
|
@ -168,16 +203,23 @@
|
|||
}
|
||||
|
||||
.description {
|
||||
color: #666;
|
||||
color: #646970;
|
||||
font-size: 13px;
|
||||
margin-top: 4px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.regular-text {
|
||||
width: 25em;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Notices */
|
||||
.notice {
|
||||
padding: 8px 12px;
|
||||
border-radius: 3px;
|
||||
border-radius: 4px;
|
||||
margin: 5px 0 15px;
|
||||
border-left: 4px solid #ddd;
|
||||
}
|
||||
|
||||
.notice p {
|
||||
|
@ -187,63 +229,85 @@
|
|||
|
||||
.notice-success {
|
||||
background-color: #f0f9eb;
|
||||
border-left: 4px solid #46b450;
|
||||
border-left-color: #46b450;
|
||||
}
|
||||
|
||||
.notice-error {
|
||||
background-color: #fef0f0;
|
||||
border-left: 4px solid #dc3232;
|
||||
border-left-color: #dc3232;
|
||||
}
|
||||
|
||||
.notice-warning {
|
||||
background-color: #fff8e5;
|
||||
border-left: 4px solid #ffb900;
|
||||
border-left-color: #ffb900;
|
||||
}
|
||||
|
||||
.notice-info {
|
||||
background-color: #f0f6fa;
|
||||
border-left: 4px solid #00a0d2;
|
||||
border-left-color: #00a0d2;
|
||||
}
|
||||
|
||||
.notice.inline {
|
||||
display: block;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
/* DNS instructions */
|
||||
.dns-instructions {
|
||||
margin-top: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.dns-instructions h3 {
|
||||
color: #1d2327;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.dns-example {
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 3px;
|
||||
background: #f6f7f7;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.dns-example h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.dns-example table {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dns-tips {
|
||||
list-style: disc;
|
||||
margin-left: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.dns-tips li {
|
||||
margin-bottom: 8px;
|
||||
color: #50575e;
|
||||
}
|
||||
|
||||
/* Status indicators */
|
||||
.dashicons-yes-alt,
|
||||
.dashicons-no-alt {
|
||||
font-size: 24px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
.dashicons-no-alt,
|
||||
.dashicons-warning,
|
||||
.dashicons-minus {
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* Logs table styles */
|
||||
.logs-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 15px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.logs-table .column-user,
|
||||
|
@ -261,41 +325,49 @@
|
|||
|
||||
.log-action {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.log-action-add {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
background-color: #d1e7dd;
|
||||
color: #0f5132;
|
||||
}
|
||||
|
||||
.log-action-edit {
|
||||
background-color: #d9edf7;
|
||||
color: #31708f;
|
||||
background-color: #cce7ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.log-action-delete {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.log-action-import {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
/* Health details */
|
||||
.health-details-content {
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 3px;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.health-details-content h4 {
|
||||
margin-top: 0;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
/* Progress bar */
|
||||
.progress-bar-outer {
|
||||
background-color: #f0f0f1;
|
||||
background-color: #e9ecef;
|
||||
border-radius: 4px;
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
|
@ -304,18 +376,30 @@
|
|||
}
|
||||
|
||||
.progress-bar-inner {
|
||||
background-color: #2271b1;
|
||||
background: linear-gradient(90deg, #2271b1 0%, #72aee6 100%);
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
transition: width 0.3s ease;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
color: #1d2327;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Import/Export specific */
|
||||
.export-section,
|
||||
.import-section {
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.import-summary,
|
||||
.import-details {
|
||||
margin-top: 15px;
|
||||
|
@ -337,11 +421,414 @@
|
|||
background-color: #fff8e5;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
/* Buttons */
|
||||
.button {
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
border: 1px solid;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
line-height: 2.15384615;
|
||||
margin: 0;
|
||||
padding: 0 10px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
background: #2271b1;
|
||||
border-color: #2271b1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button-primary:hover,
|
||||
.button-primary:focus {
|
||||
background: #135e96;
|
||||
border-color: #135e96;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button-secondary {
|
||||
background: #f6f7f7;
|
||||
border-color: #dcdcde;
|
||||
color: #50575e;
|
||||
}
|
||||
|
||||
.button-secondary:hover,
|
||||
.button-secondary:focus {
|
||||
background: #f0f0f1;
|
||||
border-color: #8c8f94;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.button-small {
|
||||
font-size: 11px;
|
||||
height: auto;
|
||||
line-height: 1.5;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.button:disabled,
|
||||
.button[disabled] {
|
||||
background: #f6f7f7 !important;
|
||||
border-color: #dcdcde !important;
|
||||
color: #a7aaad !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Health check specific buttons */
|
||||
.check-domain-health {
|
||||
font-size: 11px;
|
||||
padding: 4px 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Table row hover effects */
|
||||
.wp-list-table tbody tr:hover {
|
||||
background-color: #f6f7f7;
|
||||
}
|
||||
|
||||
.wp-list-table tbody tr.hover {
|
||||
background-color: #f0f6fa;
|
||||
}
|
||||
|
||||
/* Bulk actions */
|
||||
.bulkactions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.bulkactions select {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Row actions */
|
||||
.row-actions {
|
||||
visibility: hidden;
|
||||
padding: 2px 0 0;
|
||||
color: #646970;
|
||||
}
|
||||
|
||||
.wp-list-table tbody tr:hover .row-actions {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.row-actions span {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.row-actions a {
|
||||
color: #2271b1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.row-actions a:hover {
|
||||
color: #135e96;
|
||||
}
|
||||
|
||||
/* Dashboard Widget Styles */
|
||||
.dm-dashboard-widget {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.dm-dashboard-widget > div {
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dm-dashboard-widget > div:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.dm-dashboard-widget h4 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1d2327;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.dm-domain-primary {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dm-domain-primary a {
|
||||
text-decoration: none;
|
||||
color: #2271b1;
|
||||
}
|
||||
|
||||
.dm-domain-primary a:hover {
|
||||
color: #135e96;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.dm-no-primary {
|
||||
color: #646970;
|
||||
font-style: italic;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dm-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dm-stat {
|
||||
background: #f0f0f1;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dm-stat-value {
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #2271b1;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.dm-stat-label {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
color: #646970;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.dm-domains-list ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.dm-domains-list li {
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.dm-domains-list a {
|
||||
text-decoration: none;
|
||||
color: #50575e;
|
||||
}
|
||||
|
||||
.dm-domains-list a:hover {
|
||||
color: #2271b1;
|
||||
}
|
||||
|
||||
.dm-badge-primary {
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.dm-health-status {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dm-refresh-health {
|
||||
padding: 2px 4px !important;
|
||||
min-height: 24px !important;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
.dm-refresh-health .dashicons {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.dm-health-good {
|
||||
color: #46b450;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dm-health-issues {
|
||||
background: #fcf0f1;
|
||||
border: 1px solid #f0c4c6;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.dm-issue-item {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.dm-issue-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dm-issue-list {
|
||||
color: #d63638;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dm-last-check {
|
||||
margin: 8px 0 0;
|
||||
font-size: 12px;
|
||||
color: #646970;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.dm-dns-info code {
|
||||
background: #f0f0f1;
|
||||
padding: 3px 6px;
|
||||
border-radius: 3px;
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dm-activity-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.dm-activity-list li {
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid #f0f0f1;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dm-activity-list li:last-child {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.dm-activity-action {
|
||||
display: inline-block;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.dm-action-add {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
}
|
||||
|
||||
.dm-action-edit {
|
||||
background-color: #d9edf7;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
.dm-action-delete {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
.dm-activity-domain {
|
||||
font-weight: 500;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.dm-activity-meta {
|
||||
display: block;
|
||||
color: #646970;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.dm-quick-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.dm-quick-actions .button {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.dm-quick-actions .dashicons {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.dm-loading {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.dm-loading::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: -10px 0 0 -10px;
|
||||
border: 2px solid #f0f0f1;
|
||||
border-top-color: #2271b1;
|
||||
border-radius: 50%;
|
||||
animation: dm-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes dm-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media screen and (max-width: 782px) {
|
||||
.domain-mapping-tabs {
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.domain-mapping-tab {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.domain-mapping-tab.active {
|
||||
border-color: #2271b1;
|
||||
border-left: 4px solid #2271b1;
|
||||
}
|
||||
|
||||
.domain-mapping-tab.active::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.domain-mapping-content {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.search-form-field {
|
||||
|
@ -353,9 +840,11 @@
|
|||
max-width: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.form-table th {
|
||||
width: 100%;
|
||||
display: block;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-table td {
|
||||
|
@ -363,20 +852,25 @@
|
|||
padding: 0 0 15px;
|
||||
}
|
||||
|
||||
.domain-mapping-tabs {
|
||||
.dm-stats-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.dm-stat {
|
||||
padding: 8px 5px;
|
||||
}
|
||||
|
||||
.dm-stat-value {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.dm-quick-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.domain-mapping-tab {
|
||||
.dm-quick-actions .button {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.domain-mapping-tab.active {
|
||||
border-bottom: 1px solid #007cba;
|
||||
border-left: 4px solid #007cba;
|
||||
}
|
||||
|
||||
/* Hide less important columns on mobile */
|
||||
|
@ -391,9 +885,19 @@
|
|||
.wp-list-table td.column-actions {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.tablenav {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tablenav-pages {
|
||||
margin-left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 在文件末尾添加移动端优化 */
|
||||
@media screen and (max-width: 600px) {
|
||||
.wp-list-table {
|
||||
font-size: 12px;
|
||||
|
@ -405,11 +909,24 @@
|
|||
}
|
||||
|
||||
.domain-mapping-card {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.domain-mapping-content {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 添加验证消息样式 */
|
||||
/* Widget specific styles */
|
||||
#dm_domain_status_widget .postbox-header {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
#dm_domain_status_widget.closed .inside {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Domain validation feedback */
|
||||
#domain-validation-message {
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
|
@ -421,3 +938,99 @@
|
|||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
#domain-validation-message.success {
|
||||
background-color: #d1e7dd;
|
||||
color: #0f5132;
|
||||
border: 1px solid #badbcc;
|
||||
}
|
||||
|
||||
/* Animation utilities */
|
||||
.fade-in {
|
||||
animation: fadeIn 0.3s ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.slide-in {
|
||||
animation: slideIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accessibility improvements */
|
||||
.screen-reader-text {
|
||||
border: 0;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
clip-path: inset(50%);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute !important;
|
||||
width: 1px;
|
||||
word-wrap: normal !important;
|
||||
}
|
||||
|
||||
/* Focus styles */
|
||||
.domain-mapping-tab:focus,
|
||||
.button:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
box-shadow: 0 0 0 2px #2271b1;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Loading states */
|
||||
.button.loading {
|
||||
position: relative;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.button.loading::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -8px 0 0 -8px;
|
||||
border: 2px solid transparent;
|
||||
border-top-color: currentColor;
|
||||
border-radius: 50%;
|
||||
animation: dm-spin 1s linear infinite;
|
||||
}
|
||||
|
||||
/* High contrast mode support */
|
||||
@media (prefers-contrast: high) {
|
||||
.domain-mapping-tab.active {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.notice {
|
||||
border-left-width: 6px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ jQuery(document).ready(function($) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Basic domain format validation
|
||||
var domainPattern = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$/;
|
||||
// Enhanced domain format validation - more flexible validation
|
||||
var domainPattern = /^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]\.[a-zA-Z]{2,}$/;
|
||||
if (!domainPattern.test(domain)) {
|
||||
e.preventDefault();
|
||||
showNotice('#edit-domain-status', 'Please enter a valid domain format (e.g., example.com)', 'error');
|
||||
showNotice('#edit-domain-status', 'Please enter a valid domain format (e.g., example.com, www.example.com)', 'error');
|
||||
$('#domain').focus();
|
||||
return false;
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ jQuery(document).ready(function($) {
|
|||
$feedback.html('<span style="color: #dc3232;">Please remove http:// or https://</span>').show();
|
||||
} else if (domain.indexOf('/') !== -1) {
|
||||
$feedback.html('<span style="color: #dc3232;">Please remove any paths or slashes</span>').show();
|
||||
} else if (!/^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$/.test(domain)) {
|
||||
} else if (!/^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]\.[a-zA-Z]{2,}$/.test(domain)) {
|
||||
$feedback.html('<span style="color: #dc3232;">Please enter a valid domain format</span>').show();
|
||||
} else {
|
||||
$feedback.html('<span style="color: #46b450;">Domain format looks good</span>').show();
|
||||
|
@ -586,10 +586,11 @@ jQuery(document).ready(function($) {
|
|||
// Initialize when document is ready
|
||||
initializePage();
|
||||
});
|
||||
|
||||
// Domain Mapping Dashboard Widget JavaScript
|
||||
jQuery(document).ready(function($) {
|
||||
|
||||
// 健康状态刷新按钮
|
||||
// Health status refresh button
|
||||
$(document).on('click', '.dm-refresh-health', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -600,7 +601,7 @@ jQuery(document).ready(function($) {
|
|||
$button.prop('disabled', true);
|
||||
$healthContent.addClass('dm-loading');
|
||||
|
||||
// 旋转图标
|
||||
// Rotate icon
|
||||
$button.find('.dashicons').addClass('dashicons-update-spin');
|
||||
|
||||
$.ajax({
|
||||
|
@ -615,7 +616,7 @@ jQuery(document).ready(function($) {
|
|||
if (response.success) {
|
||||
$healthContent.html(response.data.html);
|
||||
|
||||
// 显示成功消息
|
||||
// Show success message
|
||||
var $notice = $('<div class="notice notice-success is-dismissible"><p>' +
|
||||
response.data.message + '</p></div>');
|
||||
$('#dm_domain_status_widget .inside').prepend($notice);
|
||||
|
@ -635,7 +636,7 @@ jQuery(document).ready(function($) {
|
|||
});
|
||||
});
|
||||
|
||||
// 检查所有域名健康状态
|
||||
// Check all domain health status
|
||||
$(document).on('click', '.dm-check-all-health', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -658,12 +659,12 @@ jQuery(document).ready(function($) {
|
|||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// 刷新健康状态区域
|
||||
// Refresh health status area
|
||||
if ($('#dm-widget-health-status').length) {
|
||||
$('#dm-widget-health-status .dm-health-content').html(response.data.html);
|
||||
}
|
||||
|
||||
// 显示成功消息
|
||||
// Show success message
|
||||
var $notice = $('<div class="notice notice-success is-dismissible"><p>' +
|
||||
response.data.message + '</p></div>');
|
||||
$('#dm_domain_status_widget .inside').prepend($notice);
|
||||
|
@ -686,27 +687,27 @@ jQuery(document).ready(function($) {
|
|||
});
|
||||
});
|
||||
|
||||
// 自动刷新(可选)
|
||||
// Auto-refresh (optional)
|
||||
if ($('#dm_domain_status_widget').length && $('#dm_domain_status_widget').is(':visible')) {
|
||||
// 每10分钟自动刷新一次
|
||||
// Auto-refresh every 10 minutes
|
||||
var autoRefreshInterval = setInterval(function() {
|
||||
if ($('#dm_domain_status_widget').is(':visible')) {
|
||||
$('.dm-refresh-health').first().trigger('click');
|
||||
}
|
||||
}, 600000); // 10分钟
|
||||
}, 600000); // 10 minutes
|
||||
|
||||
// 页面卸载时清除定时器
|
||||
// Clear timer on page unload
|
||||
$(window).on('beforeunload', function() {
|
||||
clearInterval(autoRefreshInterval);
|
||||
});
|
||||
}
|
||||
|
||||
// 小工具配置保存
|
||||
// Widget configuration save
|
||||
$(document).on('submit', '#dm_domain_status_widget form', function(e) {
|
||||
// 配置会自动保存,这里可以添加额外的处理
|
||||
// Configuration will auto-save, here we can add additional processing
|
||||
var showHealth = $('#dm_widget_show_health').is(':checked');
|
||||
|
||||
// 如果取消勾选健康状态,隐藏相关区域
|
||||
// If unchecked health status, hide related areas
|
||||
if (!showHealth) {
|
||||
$('#dm-widget-health-status').fadeOut();
|
||||
} else {
|
||||
|
@ -714,14 +715,14 @@ jQuery(document).ready(function($) {
|
|||
}
|
||||
});
|
||||
|
||||
// 为域名链接添加外部图标
|
||||
// Add external icons for domain links
|
||||
$('.dm-domains-list a, .dm-domain-primary a').each(function() {
|
||||
if (!$(this).find('.dashicons-external').length) {
|
||||
$(this).append(' <span class="dashicons dashicons-external" style="font-size: 14px; vertical-align: middle;"></span>');
|
||||
}
|
||||
});
|
||||
|
||||
// 工具提示
|
||||
// Tooltips
|
||||
if ($.fn.tooltip) {
|
||||
$('#dm_domain_status_widget [title]').tooltip({
|
||||
position: {
|
||||
|
|
|
@ -822,33 +822,52 @@ class WP_Domain_Mapping_Admin {
|
|||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for domain actions
|
||||
* UPDATED: Support editing domain names and better conflict checking
|
||||
* AJAX handler for domain actions - IMPROVED SECURITY
|
||||
*/
|
||||
public function ajax_handle_actions() {
|
||||
check_ajax_referer( 'domain_mapping', 'nonce' );
|
||||
// Verify nonce first
|
||||
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'domain_mapping' ) ) {
|
||||
wp_send_json_error( __( 'Security check failed.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if ( ! current_user_can( 'manage_network' ) ) {
|
||||
wp_send_json_error( __( 'Permission denied.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$action = sanitize_text_field( $_POST['action_type'] );
|
||||
$domain = dm_clean_domain( sanitize_text_field( isset( $_POST['domain'] ) ? strtolower( $_POST['domain'] ) : '' ) );
|
||||
// Sanitize and validate inputs
|
||||
$action = isset( $_POST['action_type'] ) ? sanitize_key( $_POST['action_type'] ) : '';
|
||||
$domain = isset( $_POST['domain'] ) ? dm_clean_domain( sanitize_text_field( $_POST['domain'] ) ) : '';
|
||||
$blog_id = isset( $_POST['blog_id'] ) ? absint( $_POST['blog_id'] ) : 0;
|
||||
$active = isset( $_POST['active'] ) ? absint( $_POST['active'] ) : 0;
|
||||
$orig_domain = isset( $_POST['orig_domain'] ) ? dm_clean_domain( sanitize_text_field( $_POST['orig_domain'] ) ) : '';
|
||||
$current_user_id = get_current_user_id();
|
||||
|
||||
// Validate action type
|
||||
$allowed_actions = array( 'save', 'delete' );
|
||||
if ( ! in_array( $action, $allowed_actions ) ) {
|
||||
wp_send_json_error( __( 'Invalid action.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
switch ( $action ) {
|
||||
case 'save':
|
||||
if ( $blog_id != 0 && $blog_id != 1 ) {
|
||||
// Enhanced validation for save action
|
||||
if ( $blog_id <= 0 || $blog_id === 1 ) {
|
||||
wp_send_json_error( __( 'Invalid site ID.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
// Validate domain format
|
||||
if ( ! dm_validate_domain( $domain ) ) {
|
||||
if ( empty( $domain ) || ! dm_validate_domain( $domain ) ) {
|
||||
wp_send_json_error( __( 'Invalid domain format.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
// Check if blog exists
|
||||
if ( ! get_blog_details( $blog_id ) ) {
|
||||
wp_send_json_error( __( 'Site does not exist.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
// For editing, check if domain changed
|
||||
$domain_changed = ! empty( $orig_domain ) && $orig_domain !== $domain;
|
||||
|
||||
|
@ -859,8 +878,8 @@ class WP_Domain_Mapping_Admin {
|
|||
if ( $exists ) {
|
||||
wp_send_json_error( sprintf(
|
||||
__( 'Domain %s is already mapped to site ID %d.', 'wp-domain-mapping' ),
|
||||
$domain,
|
||||
$exists->blog_id
|
||||
esc_html( $domain ),
|
||||
intval( $exists->blog_id )
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -888,10 +907,10 @@ class WP_Domain_Mapping_Admin {
|
|||
array( 'active' => 0 ),
|
||||
array(
|
||||
'blog_id' => $blog_id,
|
||||
'domain !=' => $domain
|
||||
'domain' => array( 'NOT LIKE', $domain )
|
||||
),
|
||||
array( '%d' ),
|
||||
array( '%d', '%s' )
|
||||
array( '%d' )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -905,9 +924,14 @@ class WP_Domain_Mapping_Admin {
|
|||
wp_send_json_error( __( 'Failed to add domain.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
} else {
|
||||
// Update existing domain
|
||||
// Validate original domain exists
|
||||
$orig_exists = dm_get_domain_by_name( $orig_domain );
|
||||
if ( ! $orig_exists || $orig_exists->blog_id != $blog_id ) {
|
||||
$wpdb->query( 'ROLLBACK' );
|
||||
wp_send_json_error( __( 'Original domain not found or access denied.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
// Prepare update data
|
||||
// Update existing domain
|
||||
$update_data = array(
|
||||
'blog_id' => $blog_id,
|
||||
'active' => $active
|
||||
|
@ -952,30 +976,40 @@ class WP_Domain_Mapping_Admin {
|
|||
}
|
||||
} catch ( Exception $e ) {
|
||||
$wpdb->query( 'ROLLBACK' );
|
||||
error_log( 'Domain mapping error: ' . $e->getMessage() );
|
||||
wp_send_json_error( __( 'An error occurred while saving domain.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
} else {
|
||||
wp_send_json_error( __( 'Invalid site ID.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
$domains = isset( $_POST['domains'] ) ? array_map( 'sanitize_text_field', (array) $_POST['domains'] ) : array( $domain );
|
||||
|
||||
// Validate domains array
|
||||
$domains = array_filter( $domains, function( $d ) {
|
||||
return ! empty( $d ) && dm_validate_domain( $d );
|
||||
});
|
||||
|
||||
if ( empty( $domains ) ) {
|
||||
wp_send_json_error( __( 'No valid domains provided for deletion.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
$wpdb->query( 'START TRANSACTION' );
|
||||
$deleted = 0;
|
||||
|
||||
try {
|
||||
foreach ( $domains as $del_domain ) {
|
||||
if ( empty( $del_domain ) ) continue;
|
||||
// Get domain info before deletion for logging and validation
|
||||
$domain_info = dm_get_domain_by_name( $del_domain );
|
||||
|
||||
// Get blog_id before deletion for logging
|
||||
$affected_blog_id = $wpdb->get_var( $wpdb->prepare(
|
||||
"SELECT blog_id FROM {$this->tables['domains']} WHERE domain = %s",
|
||||
$del_domain
|
||||
));
|
||||
if ( ! $domain_info ) {
|
||||
continue; // Skip non-existent domains
|
||||
}
|
||||
|
||||
// Check if user has permission to delete this domain
|
||||
if ( ! current_user_can( 'manage_network' ) ) {
|
||||
continue; // Skip if no permission
|
||||
}
|
||||
|
||||
if ( $affected_blog_id ) {
|
||||
// Delete the domain
|
||||
$result = $wpdb->delete(
|
||||
$this->tables['domains'],
|
||||
|
@ -985,10 +1019,8 @@ class WP_Domain_Mapping_Admin {
|
|||
|
||||
if ( $result ) {
|
||||
$deleted++;
|
||||
|
||||
// Log the action
|
||||
dm_log_action( 'delete', $del_domain, $affected_blog_id, $current_user_id );
|
||||
}
|
||||
dm_log_action( 'delete', $del_domain, $domain_info->blog_id, $current_user_id );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1010,6 +1042,7 @@ class WP_Domain_Mapping_Admin {
|
|||
}
|
||||
} catch ( Exception $e ) {
|
||||
$wpdb->query( 'ROLLBACK' );
|
||||
error_log( 'Domain mapping deletion error: ' . $e->getMessage() );
|
||||
wp_send_json_error( __( 'An error occurred while deleting domains.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
break;
|
||||
|
@ -1313,7 +1346,7 @@ class WP_Domain_Mapping_Admin {
|
|||
if ( ! get_site_option( 'dm_ipaddress' ) && ! get_site_option( 'dm_cname' ) ) {
|
||||
if ( dm_is_site_admin() ) {
|
||||
echo wp_kses(
|
||||
__( "Please set the IP address or CNAME of your server in the <a href='wpmu-admin.php?page=domain-mapping'>site admin page</a>.", 'wp-domain-mapping' ),
|
||||
__( "Please set the IP address or CNAME of your server in the <a href='wp-admin/network/settings.php?page=domain-mapping'>site admin page</a>.", 'wp-domain-mapping' ),
|
||||
array( 'a' => array( 'href' => array() ) )
|
||||
);
|
||||
} else {
|
||||
|
@ -1355,7 +1388,7 @@ class WP_Domain_Mapping_Admin {
|
|||
* @return array Modified columns
|
||||
*/
|
||||
public function add_domain_mapping_columns( $columns ) {
|
||||
$columns['map'] = __( 'Mapping' );
|
||||
$columns['map'] = __( 'Mapping', 'wp-domain-mapping' );
|
||||
return $columns;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ class WP_Domain_Mapping_Core {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create required database tables
|
||||
* Create required database tables - OPTIMIZED
|
||||
*/
|
||||
public function create_tables() {
|
||||
global $wpdb;
|
||||
|
@ -127,7 +127,7 @@ class WP_Domain_Mapping_Core {
|
|||
$created = 0;
|
||||
$charset_collate = $wpdb->get_charset_collate();
|
||||
|
||||
// Create domain_mapping table
|
||||
// Create domain_mapping table - IMPROVED INDEXES
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$this->tables['domains']}'" ) != $this->tables['domains'] ) {
|
||||
$wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['domains']}` (
|
||||
`id` bigint(20) NOT NULL auto_increment,
|
||||
|
@ -135,24 +135,29 @@ class WP_Domain_Mapping_Core {
|
|||
`domain` varchar(255) NOT NULL,
|
||||
`active` tinyint(4) default '1',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `blog_id` (`blog_id`,`domain`,`active`)
|
||||
UNIQUE KEY `domain` (`domain`),
|
||||
KEY `blog_id` (`blog_id`),
|
||||
KEY `blog_active` (`blog_id`, `active`),
|
||||
KEY `active_domain` (`active`, `domain`)
|
||||
) $charset_collate;" );
|
||||
$created = 1;
|
||||
}
|
||||
|
||||
// Create domain_mapping_logins table
|
||||
// Create domain_mapping_logins table - IMPROVED INDEXES
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$this->tables['logins']}'" ) != $this->tables['logins'] ) {
|
||||
$wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['logins']}` (
|
||||
`id` varchar(32) NOT NULL,
|
||||
`user_id` bigint(20) NOT NULL,
|
||||
`blog_id` bigint(20) NOT NULL,
|
||||
`t` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `user_blog` (`user_id`, `blog_id`),
|
||||
KEY `timestamp` (`t`)
|
||||
) $charset_collate;" );
|
||||
$created = 1;
|
||||
}
|
||||
|
||||
// Create domain_mapping_logs table
|
||||
// Create domain_mapping_logs table - IMPROVED INDEXES
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$this->tables['logs']}'" ) != $this->tables['logs'] ) {
|
||||
$wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['logs']}` (
|
||||
`id` bigint(20) NOT NULL auto_increment,
|
||||
|
@ -161,7 +166,11 @@ class WP_Domain_Mapping_Core {
|
|||
`domain` varchar(255) NOT NULL,
|
||||
`blog_id` bigint(20) NOT NULL,
|
||||
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `blog_timestamp` (`blog_id`, `timestamp`),
|
||||
KEY `user_action` (`user_id`, `action`),
|
||||
KEY `domain_action` (`domain`, `action`),
|
||||
KEY `timestamp` (`timestamp`)
|
||||
) $charset_collate;" );
|
||||
$created = 1;
|
||||
}
|
||||
|
@ -475,10 +484,6 @@ class WP_Domain_Mapping_Core {
|
|||
public function remote_login_js() {
|
||||
global $current_blog, $current_user, $wpdb;
|
||||
|
||||
if (strtotime($details->t) < (time() - 300)) {
|
||||
wp_die(__('Login key expired', 'wp-domain-mapping'));
|
||||
}
|
||||
|
||||
if ( 0 == get_site_option( 'dm_remote_login' ) ) {
|
||||
return;
|
||||
}
|
||||
|
@ -525,6 +530,11 @@ class WP_Domain_Mapping_Core {
|
|||
));
|
||||
|
||||
if ( $details ) {
|
||||
// FIX: Add time validation that was missing
|
||||
if ( strtotime( $details->t ) < ( time() - 300 ) ) {
|
||||
wp_die( __( 'Login key expired', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
if ( $details->blog_id == $wpdb->blogid ) {
|
||||
$wpdb->delete(
|
||||
$this->tables['logins'],
|
||||
|
@ -559,6 +569,11 @@ class WP_Domain_Mapping_Core {
|
|||
));
|
||||
|
||||
if ( $details ) {
|
||||
// FIX: Add time validation for logout too
|
||||
if ( strtotime( $details->t ) < ( time() - 300 ) ) {
|
||||
wp_die( __( 'Logout key expired', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
$wpdb->delete(
|
||||
$this->tables['logins'],
|
||||
array( 'id' => $_GET['k'] ),
|
||||
|
|
|
@ -94,6 +94,14 @@ class WP_Domain_Mapping_Tools {
|
|||
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' ) );
|
||||
|
||||
// Add debug hooks
|
||||
add_action( 'admin_notices', array( $this, 'show_cron_debug_info' ) );
|
||||
|
||||
// Add manual trigger cron hook (only for debugging)
|
||||
if ( isset( $_GET['dm_test_cron'] ) && current_user_can( 'manage_network' ) ) {
|
||||
add_action( 'admin_init', array( $this, 'test_cron_execution' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,32 +286,56 @@ class WP_Domain_Mapping_Tools {
|
|||
}
|
||||
|
||||
// ========================================
|
||||
// Health Check Functions
|
||||
// Health Check Functions - IMPROVED
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Schedule health check
|
||||
* Schedule health check - improved version
|
||||
*/
|
||||
public function schedule_health_check() {
|
||||
if ( ! wp_next_scheduled( 'dm_domain_health_check' ) ) {
|
||||
wp_schedule_event( time(), 'daily', 'dm_domain_health_check' );
|
||||
// First clear existing schedules
|
||||
$this->unschedule_health_check();
|
||||
|
||||
// Check if setting is enabled
|
||||
if ( ! get_site_option( 'dm_health_check_enabled', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set next execution time (tomorrow at 2:00 AM)
|
||||
$next_run = strtotime( 'tomorrow 2:00 AM' );
|
||||
|
||||
// Schedule event
|
||||
$scheduled = wp_schedule_event( $next_run, 'daily', 'dm_domain_health_check' );
|
||||
|
||||
// Log scheduling status
|
||||
if ( $scheduled !== false ) {
|
||||
error_log( 'WP Domain Mapping: Health check scheduled for ' . date( 'Y-m-d H:i:s', $next_run ) );
|
||||
} else {
|
||||
error_log( 'WP Domain Mapping: Failed to schedule health check' );
|
||||
}
|
||||
|
||||
// Also set an option to track scheduling status
|
||||
update_site_option( 'dm_health_check_scheduled', array(
|
||||
'scheduled_at' => current_time( 'timestamp' ),
|
||||
'next_run' => $next_run,
|
||||
'status' => $scheduled !== false ? 'scheduled' : 'failed'
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unschedule health check
|
||||
* Unschedule health check - improved version
|
||||
*/
|
||||
public function unschedule_health_check() {
|
||||
$timestamp = wp_next_scheduled( 'dm_domain_health_check' );
|
||||
if ( $timestamp ) {
|
||||
wp_unschedule_event( $timestamp, 'dm_domain_health_check' );
|
||||
}
|
||||
// Clear main health check
|
||||
wp_clear_scheduled_hook( 'dm_domain_health_check' );
|
||||
|
||||
// Also clear any batch processing
|
||||
$timestamp = wp_next_scheduled( 'dm_domain_health_check_batch' );
|
||||
if ( $timestamp ) {
|
||||
wp_unschedule_event( $timestamp, 'dm_domain_health_check_batch' );
|
||||
}
|
||||
// Clear batch processing health check
|
||||
wp_clear_scheduled_hook( 'dm_domain_health_check_batch' );
|
||||
|
||||
// Clear scheduling status option
|
||||
delete_site_option( 'dm_health_check_scheduled' );
|
||||
|
||||
error_log( 'WP Domain Mapping: Health check unscheduled' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -443,15 +475,25 @@ class WP_Domain_Mapping_Tools {
|
|||
}
|
||||
|
||||
/**
|
||||
* Scheduled health check
|
||||
* Scheduled health check - improved version
|
||||
*/
|
||||
public function scheduled_health_check() {
|
||||
// Log execution start
|
||||
error_log( 'WP Domain Mapping: Starting scheduled health check at ' . current_time( 'mysql' ) );
|
||||
|
||||
// Check if health checks are enabled
|
||||
if ( ! get_site_option( 'dm_health_check_enabled', true ) ) {
|
||||
error_log( 'WP Domain Mapping: Health check is disabled, skipping' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Update last execution time
|
||||
update_site_option( 'dm_last_health_check', current_time( 'timestamp' ) );
|
||||
|
||||
// Start batch processing
|
||||
$this->start_health_check_batch();
|
||||
|
||||
error_log( 'WP Domain Mapping: Scheduled health check batch started' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -821,6 +863,73 @@ class WP_Domain_Mapping_Tools {
|
|||
wp_mail( $notification_email, $subject, $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new method: check cron status
|
||||
*/
|
||||
public function get_cron_status() {
|
||||
$scheduled_info = get_site_option( 'dm_health_check_scheduled', false );
|
||||
$next_scheduled = wp_next_scheduled( 'dm_domain_health_check' );
|
||||
$last_check = get_site_option( 'dm_last_health_check', false );
|
||||
|
||||
return array(
|
||||
'scheduled_info' => $scheduled_info,
|
||||
'next_scheduled' => $next_scheduled,
|
||||
'next_scheduled_formatted' => $next_scheduled ? date( 'Y-m-d H:i:s', $next_scheduled ) : 'Not scheduled',
|
||||
'last_check' => $last_check,
|
||||
'last_check_formatted' => $last_check ? date( 'Y-m-d H:i:s', $last_check ) : 'Never',
|
||||
'wp_cron_disabled' => defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON,
|
||||
'cron_running' => ! defined( 'DISABLE_WP_CRON' ) || ! DISABLE_WP_CRON
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show cron debug info (only show on network admin pages)
|
||||
*/
|
||||
public function show_cron_debug_info() {
|
||||
if ( ! is_network_admin() || ! current_user_can( 'manage_network' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_screen = get_current_screen();
|
||||
if ( ! $current_screen || $current_screen->id !== 'settings_page_domain-mapping-network' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$status = $this->get_cron_status();
|
||||
|
||||
if ( $status['wp_cron_disabled'] ) {
|
||||
echo '<div class="notice notice-warning"><p>';
|
||||
echo '<strong>WP Domain Mapping:</strong> WordPress Cron is disabled (DISABLE_WP_CRON = true). ';
|
||||
echo 'Automatic health checks will not work. Please set up a system cron job.';
|
||||
echo '</p></div>';
|
||||
}
|
||||
|
||||
// Show next execution time (only in debug mode)
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
echo '<div class="notice notice-info"><p>';
|
||||
echo '<strong>Health Check Status:</strong><br>';
|
||||
echo 'Next scheduled: ' . esc_html( $status['next_scheduled_formatted'] ) . '<br>';
|
||||
echo 'Last check: ' . esc_html( $status['last_check_formatted'] ) . '<br>';
|
||||
echo '<a href="' . add_query_arg( 'dm_test_cron', '1' ) . '">Test Cron Execution</a>';
|
||||
echo '</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cron execution (only for debugging)
|
||||
*/
|
||||
public function test_cron_execution() {
|
||||
if ( ! isset( $_GET['dm_test_cron'] ) || ! current_user_can( 'manage_network' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Manually trigger health check
|
||||
$this->scheduled_health_check();
|
||||
|
||||
wp_redirect( remove_query_arg( 'dm_test_cron' ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Import/Export Functions
|
||||
// ========================================
|
||||
|
@ -899,7 +1008,7 @@ class WP_Domain_Mapping_Tools {
|
|||
wp_send_json_error( __( 'Invalid security token. Please try again.', 'wp-domain-mapping' ) );
|
||||
}
|
||||
|
||||
// 在处理文件之前添加:
|
||||
// Check file size before processing
|
||||
if ($_FILES['csv_file']['size'] > 5 * 1024 * 1024) {
|
||||
wp_send_json_error(__('File size exceeds 5MB limit.', 'wp-domain-mapping'));
|
||||
return;
|
||||
|
@ -915,7 +1024,7 @@ class WP_Domain_Mapping_Tools {
|
|||
$update_existing = isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false;
|
||||
$validate_sites = isset( $_POST['validate_sites'] ) ? (bool) $_POST['validate_sites'] : true;
|
||||
|
||||
// 验证文件类型
|
||||
// Validate file type
|
||||
$file_type = wp_check_filetype($_FILES['csv_file']['name']);
|
||||
if (!in_array($file_type['ext'], array('csv', 'txt'))) {
|
||||
wp_send_json_error(__('Only CSV files are allowed.', 'wp-domain-mapping'));
|
||||
|
|
|
@ -25,7 +25,7 @@ function dm_ensure_protocol( $domain ) {
|
|||
|
||||
/**
|
||||
* Clean domain name (remove protocol and trailing slash)
|
||||
* UPDATED: Keep www prefix to distinguish www.domain.com from domain.com
|
||||
* UPDATED: Improved domain cleaning function, preserves www prefix
|
||||
*
|
||||
* @param string $domain Domain name
|
||||
* @return string Cleaned domain
|
||||
|
@ -49,10 +49,15 @@ function dm_clean_domain( $domain ) {
|
|||
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 );
|
||||
$ascii_domain = idn_to_ascii( $domain, 0, INTL_IDNA_VARIANT_UTS46 );
|
||||
} else {
|
||||
// PHP < 7.2
|
||||
$domain = idn_to_ascii( $domain );
|
||||
$ascii_domain = idn_to_ascii( $domain );
|
||||
}
|
||||
|
||||
// Only use converted result if conversion was successful
|
||||
if ($ascii_domain !== false) {
|
||||
$domain = $ascii_domain;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,14 +66,82 @@ function dm_clean_domain( $domain ) {
|
|||
|
||||
/**
|
||||
* Validate a domain name
|
||||
* UPDATED: Accept www prefix as valid
|
||||
* UPDATED: More flexible domain validation, supports www prefix and more valid formats
|
||||
*
|
||||
* @param string $domain The domain
|
||||
* @return bool True if valid
|
||||
*/
|
||||
function dm_validate_domain( $domain ) {
|
||||
// Basic validation - now accepts www prefix
|
||||
return (bool) preg_match( '/^(www\.)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$/i', $domain );
|
||||
// Remove possible protocol and path
|
||||
$domain = preg_replace('#^https?://#', '', $domain);
|
||||
$domain = preg_replace('#/.*$#', '', $domain);
|
||||
$domain = trim($domain);
|
||||
|
||||
// Check if empty
|
||||
if (empty($domain)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check length limit (RFC 1035)
|
||||
if (strlen($domain) > 253) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if contains only valid characters (letters, numbers, dots, hyphens)
|
||||
if (!preg_match('/^[a-zA-Z0-9.-]+$/', $domain)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if starts or ends with dot
|
||||
if (substr($domain, 0, 1) === '.' || substr($domain, -1) === '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for consecutive dots
|
||||
if (strpos($domain, '..') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Split domain into parts
|
||||
$parts = explode('.', $domain);
|
||||
|
||||
// Need at least two parts (domain.tld)
|
||||
if (count($parts) < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each part
|
||||
foreach ($parts as $part) {
|
||||
// Each part cannot be empty
|
||||
if (empty($part)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Each part cannot exceed 63 characters (RFC 1035)
|
||||
if (strlen($part) > 63) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Each part cannot start or end with hyphen
|
||||
if (substr($part, 0, 1) === '-' || substr($part, -1) === '-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Each part can only contain letters, numbers and hyphens
|
||||
if (!preg_match('/^[a-zA-Z0-9-]+$/', $part)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check TLD (last part) validity
|
||||
$tld = end($parts);
|
||||
|
||||
// TLD needs at least 2 characters and can only contain letters
|
||||
if (strlen($tld) < 2 || !preg_match('/^[a-zA-Z]+$/', $tld)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -443,20 +516,302 @@ function dm_format_action_name( $action ) {
|
|||
}
|
||||
}
|
||||
|
||||
// Cache functions
|
||||
/**
|
||||
* Enhanced caching functions for better performance
|
||||
*/
|
||||
|
||||
// Cache functions - IMPROVED
|
||||
function dm_get_domains_by_blog_id_cached($blog_id) {
|
||||
$cache_key = 'dm_domains_' . $blog_id;
|
||||
$domains = wp_cache_get($cache_key, 'domain_mapping');
|
||||
$cache_group = 'domain_mapping';
|
||||
|
||||
$domains = wp_cache_get($cache_key, $cache_group);
|
||||
|
||||
if (false === $domains) {
|
||||
$domains = dm_get_domains_by_blog_id($blog_id);
|
||||
wp_cache_set($cache_key, $domains, 'domain_mapping', HOUR_IN_SECONDS);
|
||||
// Cache for 1 hour, or until manually cleared
|
||||
wp_cache_set($cache_key, $domains, $cache_group, HOUR_IN_SECONDS);
|
||||
}
|
||||
|
||||
return $domains;
|
||||
}
|
||||
|
||||
// Clear cache function
|
||||
function dm_clear_domain_cache($blog_id) {
|
||||
wp_cache_delete('dm_domains_' . $blog_id, 'domain_mapping');
|
||||
// Clear cache function - IMPROVED
|
||||
function dm_clear_domain_cache($blog_id = null) {
|
||||
$cache_group = 'domain_mapping';
|
||||
|
||||
if ($blog_id) {
|
||||
// Clear specific blog cache
|
||||
wp_cache_delete('dm_domains_' . $blog_id, $cache_group);
|
||||
wp_cache_delete('dm_domain_exists_' . $blog_id, $cache_group);
|
||||
} else {
|
||||
// Clear all domain mapping caches
|
||||
wp_cache_flush_group($cache_group);
|
||||
}
|
||||
|
||||
// Also clear object cache if available
|
||||
if (function_exists('wp_cache_flush_group')) {
|
||||
wp_cache_flush_group($cache_group);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached domain existence check
|
||||
*/
|
||||
function dm_domain_exists_cached($domain) {
|
||||
$cache_key = 'dm_domain_exists_' . md5($domain);
|
||||
$cache_group = 'domain_mapping';
|
||||
|
||||
$exists = wp_cache_get($cache_key, $cache_group);
|
||||
|
||||
if (false === $exists) {
|
||||
$exists = dm_get_domain_by_name($domain);
|
||||
// Cache for 30 minutes
|
||||
wp_cache_set($cache_key, $exists, $cache_group, 30 * MINUTE_IN_SECONDS);
|
||||
}
|
||||
|
||||
return $exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch clear cache for multiple blogs
|
||||
*/
|
||||
function dm_clear_multiple_domain_cache($blog_ids) {
|
||||
if (!is_array($blog_ids)) {
|
||||
$blog_ids = array($blog_ids);
|
||||
}
|
||||
|
||||
foreach ($blog_ids as $blog_id) {
|
||||
dm_clear_domain_cache($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check results caching
|
||||
*/
|
||||
function dm_get_health_result_cached($domain) {
|
||||
$cache_key = 'dm_health_' . md5($domain);
|
||||
$cache_group = 'domain_mapping_health';
|
||||
|
||||
$result = wp_cache_get($cache_key, $cache_group);
|
||||
|
||||
if (false === $result) {
|
||||
$result = dm_get_health_result($domain);
|
||||
if ($result) {
|
||||
// Cache for 1 hour
|
||||
wp_cache_set($cache_key, $result, $cache_group, HOUR_IN_SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear health check cache
|
||||
*/
|
||||
function dm_clear_health_cache($domain = null) {
|
||||
$cache_group = 'domain_mapping_health';
|
||||
|
||||
if ($domain) {
|
||||
wp_cache_delete('dm_health_' . md5($domain), $cache_group);
|
||||
} else {
|
||||
if (function_exists('wp_cache_flush_group')) {
|
||||
wp_cache_flush_group($cache_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Enhanced error handling and logging functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Log domain mapping errors
|
||||
*/
|
||||
function dm_log_error($message, $context = array()) {
|
||||
if (!defined('WP_DEBUG') || !WP_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
$log_message = '[WP Domain Mapping] ' . $message;
|
||||
|
||||
if (!empty($context)) {
|
||||
$log_message .= ' Context: ' . json_encode($context);
|
||||
}
|
||||
|
||||
error_log($log_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log domain mapping info
|
||||
*/
|
||||
function dm_log_info($message, $context = array()) {
|
||||
if (!defined('WP_DEBUG') || !WP_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
$log_message = '[WP Domain Mapping INFO] ' . $message;
|
||||
|
||||
if (!empty($context)) {
|
||||
$log_message .= ' Context: ' . json_encode($context);
|
||||
}
|
||||
|
||||
error_log($log_message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe database query execution
|
||||
*/
|
||||
function dm_safe_query($query, $params = array()) {
|
||||
global $wpdb;
|
||||
|
||||
try {
|
||||
if (!empty($params)) {
|
||||
$prepared = $wpdb->prepare($query, $params);
|
||||
} else {
|
||||
$prepared = $query;
|
||||
}
|
||||
|
||||
$result = $wpdb->query($prepared);
|
||||
|
||||
if ($result === false) {
|
||||
dm_log_error('Database query failed', array(
|
||||
'query' => $query,
|
||||
'params' => $params,
|
||||
'error' => $wpdb->last_error
|
||||
));
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (Exception $e) {
|
||||
dm_log_error('Database exception', array(
|
||||
'query' => $query,
|
||||
'params' => $params,
|
||||
'exception' => $e->getMessage()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced domain validation with error details
|
||||
*/
|
||||
function dm_validate_domain_with_errors($domain) {
|
||||
$errors = array();
|
||||
|
||||
// Remove possible protocol and path
|
||||
$original_domain = $domain;
|
||||
$domain = preg_replace('#^https?://#', '', $domain);
|
||||
$domain = preg_replace('#/.*$#', '', $domain);
|
||||
$domain = trim($domain);
|
||||
|
||||
// Check if empty
|
||||
if (empty($domain)) {
|
||||
$errors[] = __('Domain cannot be empty', 'wp-domain-mapping');
|
||||
return array('valid' => false, 'errors' => $errors, 'domain' => $domain);
|
||||
}
|
||||
|
||||
// Check length limit (RFC 1035)
|
||||
if (strlen($domain) > 253) {
|
||||
$errors[] = __('Domain name too long (max 253 characters)', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// Check if contains only valid characters
|
||||
if (!preg_match('/^[a-zA-Z0-9.-]+$/', $domain)) {
|
||||
$errors[] = __('Domain contains invalid characters', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// Check if starts or ends with dot
|
||||
if (substr($domain, 0, 1) === '.' || substr($domain, -1) === '.') {
|
||||
$errors[] = __('Domain cannot start or end with a dot', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// Check for consecutive dots
|
||||
if (strpos($domain, '..') !== false) {
|
||||
$errors[] = __('Domain cannot contain consecutive dots', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// Split domain into parts
|
||||
$parts = explode('.', $domain);
|
||||
|
||||
// Need at least two parts
|
||||
if (count($parts) < 2) {
|
||||
$errors[] = __('Domain must have at least two parts (e.g., domain.com)', 'wp-domain-mapping');
|
||||
}
|
||||
|
||||
// Check each part
|
||||
foreach ($parts as $i => $part) {
|
||||
if (empty($part)) {
|
||||
$errors[] = sprintf(__('Domain part %d is empty', 'wp-domain-mapping'), $i + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen($part) > 63) {
|
||||
$errors[] = sprintf(__('Domain part "%s" too long (max 63 characters)', 'wp-domain-mapping'), $part);
|
||||
}
|
||||
|
||||
if (substr($part, 0, 1) === '-' || substr($part, -1) === '-') {
|
||||
$errors[] = sprintf(__('Domain part "%s" cannot start or end with hyphen', 'wp-domain-mapping'), $part);
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9-]+$/', $part)) {
|
||||
$errors[] = sprintf(__('Domain part "%s" contains invalid characters', 'wp-domain-mapping'), $part);
|
||||
}
|
||||
}
|
||||
|
||||
// Check TLD
|
||||
if (count($parts) >= 2) {
|
||||
$tld = end($parts);
|
||||
if (strlen($tld) < 2 || !preg_match('/^[a-zA-Z]+$/', $tld)) {
|
||||
$errors[] = __('Invalid top-level domain (TLD)', 'wp-domain-mapping');
|
||||
}
|
||||
}
|
||||
|
||||
$is_valid = empty($errors);
|
||||
|
||||
// Log validation attempts if debugging
|
||||
if (!$is_valid) {
|
||||
dm_log_info('Domain validation failed', array(
|
||||
'original' => $original_domain,
|
||||
'cleaned' => $domain,
|
||||
'errors' => $errors
|
||||
));
|
||||
}
|
||||
|
||||
return array(
|
||||
'valid' => $is_valid,
|
||||
'errors' => $errors,
|
||||
'domain' => $domain,
|
||||
'original' => $original_domain
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced health check with error handling
|
||||
*/
|
||||
function dm_check_domain_health_safe($domain) {
|
||||
try {
|
||||
$tools = WP_Domain_Mapping_Tools::get_instance();
|
||||
$result = $tools->check_domain_health($domain);
|
||||
|
||||
dm_log_info('Health check completed', array(
|
||||
'domain' => $domain,
|
||||
'result' => $result
|
||||
));
|
||||
|
||||
return $result;
|
||||
} catch (Exception $e) {
|
||||
dm_log_error('Health check failed', array(
|
||||
'domain' => $domain,
|
||||
'exception' => $e->getMessage()
|
||||
));
|
||||
|
||||
return array(
|
||||
'domain' => $domain,
|
||||
'last_check' => current_time('mysql'),
|
||||
'error' => $e->getMessage(),
|
||||
'dns_status' => 'error',
|
||||
'ssl_valid' => false,
|
||||
'accessible' => false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
55
sunrise.php
55
sunrise.php
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Sunrise.php for WordPress Domain Mapping
|
||||
* Sunrise.php for WP Domain Mapping
|
||||
*
|
||||
* This file must be copied to wp-content/sunrise.php
|
||||
* Also, you must add "define('SUNRISE', 'on');" to wp-config.php
|
||||
|
@ -18,16 +18,27 @@ if (!defined('MULTISITE') || !MULTISITE) {
|
|||
// Enable domain mapping
|
||||
define('DOMAIN_MAPPING', 1);
|
||||
|
||||
// Check if we're on the main site already
|
||||
if (defined('COOKIE_DOMAIN') && COOKIE_DOMAIN == $_SERVER['HTTP_HOST']) {
|
||||
return;
|
||||
// Don't process if we're in admin and on the original domain
|
||||
if (is_admin() && isset($_SERVER['HTTP_HOST'])) {
|
||||
// Allow admin access from any domain - we'll handle this in the plugin itself
|
||||
}
|
||||
|
||||
global $wpdb, $current_blog, $current_site;
|
||||
|
||||
// Check if tables exist before proceeding
|
||||
if (!$wpdb) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get domains table name
|
||||
$domain_mapping_table = $wpdb->base_prefix . 'domain_mapping';
|
||||
|
||||
// Check if the domain mapping table exists
|
||||
$table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$domain_mapping_table}'") == $domain_mapping_table;
|
||||
if (!$table_exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for the current domain in the domain mapping table
|
||||
$domain = sanitize_text_field($_SERVER['HTTP_HOST']);
|
||||
$blog_id = $wpdb->get_var($wpdb->prepare(
|
||||
|
@ -38,14 +49,19 @@ $blog_id = $wpdb->get_var($wpdb->prepare(
|
|||
// 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");
|
||||
$mapped_blog = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->blogs} WHERE blog_id = %d LIMIT 1",
|
||||
$blog_id
|
||||
));
|
||||
|
||||
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']);
|
||||
// Set cookie domain for the mapped domain (only if not defined in wp-config.php)
|
||||
if (!defined('COOKIE_DOMAIN')) {
|
||||
define('COOKIE_DOMAIN', $domain);
|
||||
}
|
||||
|
||||
// Define the mapped domain constant
|
||||
define('MAPPED_DOMAIN', true);
|
||||
|
@ -53,12 +69,35 @@ if (!empty($blog_id)) {
|
|||
// Allow other plugins to know this is a mapped domain
|
||||
$GLOBALS['dm_domain'] = array(
|
||||
'original' => $current_blog->domain,
|
||||
'mapped' => $_SERVER['HTTP_HOST']
|
||||
'mapped' => $domain,
|
||||
'blog_id' => $blog_id
|
||||
);
|
||||
|
||||
// Fix request URI for path sites
|
||||
if ($current_blog->path != '/' && ($current_blog->path != '/wp/' || strpos($_SERVER['REQUEST_URI'], '/wp/') === false)) {
|
||||
$current_blog->path = '/';
|
||||
}
|
||||
|
||||
// Store original values for reference
|
||||
if (!defined('DM_ORIGINAL_DOMAIN')) {
|
||||
define('DM_ORIGINAL_DOMAIN', $mapped_blog->domain);
|
||||
}
|
||||
if (!defined('DM_ORIGINAL_PATH')) {
|
||||
define('DM_ORIGINAL_PATH', $mapped_blog->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if current request is for admin area
|
||||
function dm_is_admin_request() {
|
||||
if (!isset($_SERVER['REQUEST_URI'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request_uri = $_SERVER['REQUEST_URI'];
|
||||
return (
|
||||
strpos($request_uri, '/wp-admin/') !== false ||
|
||||
strpos($request_uri, '/wp-login.php') !== false ||
|
||||
(defined('WP_ADMIN') && WP_ADMIN)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Plugin Name: WP Domain Mapping
|
||||
* Plugin URI: https://wenpai.org/plugins/wp-domain-mapping/
|
||||
* Description: Map any site on a WordPress website to another domain with enhanced management features.
|
||||
* Version: 2.2.0
|
||||
* Version: 2.0.0
|
||||
* Author: WPDomain.com
|
||||
* Author URI: https://wpdomain.com/
|
||||
* Network: true
|
||||
|
@ -20,7 +20,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
}
|
||||
|
||||
// Define plugin constants
|
||||
define( 'WP_DOMAIN_MAPPING_VERSION', '2.2.0' );
|
||||
define( 'WP_DOMAIN_MAPPING_VERSION', '2.0.0' );
|
||||
define( 'WP_DOMAIN_MAPPING_DIR_URL', plugin_dir_url( __FILE__ ) );
|
||||
define( 'WP_DOMAIN_MAPPING_DIR_PATH', plugin_dir_path( __FILE__ ) );
|
||||
define( 'WP_DOMAIN_MAPPING_BASENAME', plugin_basename( __FILE__ ) );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue