v2.0 正式版发布

This commit is contained in:
文派备案 2025-05-26 22:47:52 +08:00
parent a1869ff494
commit dd5e4f04a0
12 changed files with 3705 additions and 2138 deletions

File diff suppressed because it is too large Load diff

View file

@ -358,24 +358,44 @@ settings_errors( 'dm_settings' );
</tr> </tr>
<tr> <tr>
<td> <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> <span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>
<?php else : ?> <?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> <span class="dashicons dashicons-no-alt" style="color: #dc3232;"></span>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td><?php esc_html_e( 'COOKIE_DOMAIN', 'wp-domain-mapping' ); ?></td> <td><?php esc_html_e('COOKIE_DOMAIN', 'wp-domain-mapping'); ?></td>
<td> <td>
<?php if ( ! defined( 'COOKIE_DOMAIN' ) ) : ?> <?php if ($cookie_domain_status['is_optimal']): ?>
<?php esc_html_e( 'Not defined (correct)', 'wp-domain-mapping' ); ?> <span style="color: #46b450;">
<?php else : ?> <?php echo esc_html($cookie_domain_status['message']); ?>
<?php </span>
printf( <?php elseif ($cookie_domain_status['has_warning']): ?>
/* translators: %s: COOKIE_DOMAIN constant value */ <span style="color: #f56e28;">
esc_html__( 'Defined as: %s - remove this from wp-config.php', 'wp-domain-mapping' ), <?php echo esc_html($cookie_domain_status['message']); ?>
'<code>' . esc_html( COOKIE_DOMAIN ) . '</code>' </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: ?>
<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; ?> <?php endif; ?>
</td> </td>
</tr> </tr>

View file

@ -1,4 +1,4 @@
/* WP Domain Mapping Admin Styles */ /* WP Domain Mapping Admin Styles - Optimized Layout */
/* Main cards */ /* Main cards */
.domain-mapping-card { .domain-mapping-card {
@ -9,9 +9,14 @@
margin-top: 20px; margin-top: 20px;
padding: 20px; padding: 20px;
box-shadow: 0 1px 1px rgba(0,0,0,.04); 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 { .domain-mapping-tabs {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -40,8 +45,21 @@
border-bottom-color: #dcdcde; border-bottom-color: #dcdcde;
} }
/* Tab Content */
.domain-mapping-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 */ /* Search form */
@ -50,7 +68,11 @@
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-end; align-items: flex-end;
gap: 15px; gap: 15px;
margin-bottom: 15px; margin-bottom: 20px;
padding: 20px;
background: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
} }
.search-form-field { .search-form-field {
@ -62,6 +84,7 @@
.search-form-field label { .search-form-field label {
margin-bottom: 5px; margin-bottom: 5px;
font-weight: 500; font-weight: 500;
color: #1d2327;
} }
.search-form-submit { .search-form-submit {
@ -72,9 +95,10 @@
/* Tables */ /* Tables */
.tablenav { .tablenav {
margin: 10px 0; margin: 15px 0;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
} }
.tablenav-pages { .tablenav-pages {
@ -92,23 +116,32 @@
font-weight: 400; font-weight: 400;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
border-radius: 3px;
margin: 0 2px;
} }
.tablenav-pages span.current { .tablenav-pages span.current {
background: #007cba; background: #2271b1;
color: #fff;
border-color: #2271b1;
}
.tablenav-pages a:hover {
background: #2271b1;
color: #fff; color: #fff;
border-color: #007cba;
} }
.displaying-num { .displaying-num {
margin-left: 10px; margin-left: 10px;
color: #555; color: #646970;
font-size: 13px;
} }
.domains-table th, .domains-table th,
.logs-table th, .logs-table th,
.domains-health-table th { .domains-health-table th {
font-weight: 600; font-weight: 600;
color: #1d2327;
} }
.column-site-id { .column-site-id {
@ -152,8 +185,8 @@
background: #2271b1; background: #2271b1;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
padding: 0 5px; padding: 2px 8px;
border-radius: 3px; border-radius: 4px;
font-size: 12px; font-size: 12px;
} }
@ -161,6 +194,8 @@
.form-table th { .form-table th {
width: 200px; width: 200px;
padding: 15px 10px 15px 0; padding: 15px 10px 15px 0;
font-weight: 600;
color: #1d2327;
} }
.form-table td { .form-table td {
@ -168,16 +203,23 @@
} }
.description { .description {
color: #666; color: #646970;
font-size: 13px; font-size: 13px;
margin-top: 4px; margin-top: 4px;
line-height: 1.4;
}
.regular-text {
width: 25em;
max-width: 100%;
} }
/* Notices */ /* Notices */
.notice { .notice {
padding: 8px 12px; padding: 8px 12px;
border-radius: 3px; border-radius: 4px;
margin: 5px 0 15px; margin: 5px 0 15px;
border-left: 4px solid #ddd;
} }
.notice p { .notice p {
@ -187,63 +229,85 @@
.notice-success { .notice-success {
background-color: #f0f9eb; background-color: #f0f9eb;
border-left: 4px solid #46b450; border-left-color: #46b450;
} }
.notice-error { .notice-error {
background-color: #fef0f0; background-color: #fef0f0;
border-left: 4px solid #dc3232; border-left-color: #dc3232;
} }
.notice-warning { .notice-warning {
background-color: #fff8e5; background-color: #fff8e5;
border-left: 4px solid #ffb900; border-left-color: #ffb900;
} }
.notice-info { .notice-info {
background-color: #f0f6fa; background-color: #f0f6fa;
border-left: 4px solid #00a0d2; border-left-color: #00a0d2;
}
.notice.inline {
display: block;
margin: 15px 0;
} }
/* DNS instructions */ /* DNS instructions */
.dns-instructions { .dns-instructions {
margin-top: 10px; margin-top: 15px;
}
.dns-instructions h3 {
color: #1d2327;
margin-top: 25px;
margin-bottom: 10px;
} }
.dns-example { .dns-example {
background: #f9f9f9; background: #f6f7f7;
border: 1px solid #e5e5e5; border: 1px solid #ddd;
border-radius: 3px; border-radius: 4px;
padding: 15px; padding: 15px;
margin: 15px 0; margin: 15px 0;
} }
.dns-example h4 { .dns-example h4 {
margin-top: 0; margin-top: 0;
margin-bottom: 10px;
color: #1d2327;
}
.dns-example table {
margin-top: 10px;
} }
.dns-tips { .dns-tips {
list-style: disc; list-style: disc;
margin-left: 20px; margin-left: 20px;
line-height: 1.6;
} }
.dns-tips li { .dns-tips li {
margin-bottom: 8px; margin-bottom: 8px;
color: #50575e;
} }
/* Status indicators */ /* Status indicators */
.dashicons-yes-alt, .dashicons-yes-alt,
.dashicons-no-alt { .dashicons-no-alt,
font-size: 24px; .dashicons-warning,
width: 24px; .dashicons-minus {
height: 24px; font-size: 20px;
width: 20px;
height: 20px;
} }
/* Logs table styles */ /* Logs table styles */
.logs-filter { .logs-filter {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 10px; margin-bottom: 15px;
gap: 10px;
} }
.logs-table .column-user, .logs-table .column-user,
@ -261,41 +325,49 @@
.log-action { .log-action {
display: inline-block; display: inline-block;
padding: 2px 8px; padding: 3px 8px;
border-radius: 3px; border-radius: 3px;
font-size: 12px; font-size: 11px;
font-weight: bold; font-weight: 400;
text-transform: uppercase;
} }
.log-action-add { .log-action-add {
background-color: #dff0d8; background-color: #d1e7dd;
color: #3c763d; color: #0f5132;
} }
.log-action-edit { .log-action-edit {
background-color: #d9edf7; background-color: #cce7ff;
color: #31708f; color: #004085;
} }
.log-action-delete { .log-action-delete {
background-color: #f2dede; background-color: #f8d7da;
color: #a94442; color: #721c24;
}
.log-action-import {
background-color: #fff3cd;
color: #856404;
} }
/* Health details */ /* Health details */
.health-details-content { .health-details-content {
padding: 15px; padding: 15px;
background: #f9f9f9; background: #f9f9f9;
border-radius: 3px; border-radius: 4px;
margin-top: 10px;
} }
.health-details-content h4 { .health-details-content h4 {
margin-top: 0; margin-top: 0;
color: #1d2327;
} }
/* Progress bar */ /* Progress bar */
.progress-bar-outer { .progress-bar-outer {
background-color: #f0f0f1; background-color: #e9ecef;
border-radius: 4px; border-radius: 4px;
height: 20px; height: 20px;
width: 100%; width: 100%;
@ -304,18 +376,30 @@
} }
.progress-bar-inner { .progress-bar-inner {
background-color: #2271b1; background: linear-gradient(90deg, #2271b1 0%, #72aee6 100%);
height: 100%; height: 100%;
width: 0%; width: 0%;
transition: width 0.3s ease; transition: width 0.3s ease;
border-radius: 4px 0 0 4px;
} }
.progress-text { .progress-text {
text-align: center; text-align: center;
font-weight: 500; font-weight: 500;
color: #1d2327;
margin-top: 5px;
} }
/* Import/Export specific */ /* Import/Export specific */
.export-section,
.import-section {
margin-bottom: 30px;
padding: 20px;
background: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
}
.import-summary, .import-summary,
.import-details { .import-details {
margin-top: 15px; margin-top: 15px;
@ -337,11 +421,414 @@
background-color: #fff8e5; 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) { @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 { .search-form {
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
padding: 15px;
} }
.search-form-field { .search-form-field {
@ -353,9 +840,11 @@
max-width: 100%; max-width: 100%;
width: auto; width: auto;
} }
.form-table th { .form-table th {
width: 100%; width: 100%;
display: block; display: block;
padding-bottom: 5px;
} }
.form-table td { .form-table td {
@ -363,20 +852,25 @@
padding: 0 0 15px; 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; flex-direction: column;
} }
.domain-mapping-tab { .dm-quick-actions .button {
width: 100%; 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 */ /* Hide less important columns on mobile */
@ -391,9 +885,19 @@
.wp-list-table td.column-actions { .wp-list-table td.column-actions {
display: table-cell; 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) { @media screen and (max-width: 600px) {
.wp-list-table { .wp-list-table {
font-size: 12px; font-size: 12px;
@ -405,11 +909,24 @@
} }
.domain-mapping-card { .domain-mapping-card {
margin-top: 15px;
}
.domain-mapping-content {
padding: 15px; 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 { #domain-validation-message {
margin-top: 5px; margin-top: 5px;
padding: 5px; padding: 5px;
@ -421,3 +938,99 @@
color: #721c24; color: #721c24;
border: 1px solid #f5c6cb; 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;
}
}

View file

@ -33,11 +33,11 @@ jQuery(document).ready(function($) {
return false; return false;
} }
// Basic domain format validation // Enhanced domain format validation - more flexible validation
var domainPattern = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$/; var domainPattern = /^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]\.[a-zA-Z]{2,}$/;
if (!domainPattern.test(domain)) { if (!domainPattern.test(domain)) {
e.preventDefault(); 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(); $('#domain').focus();
return false; return false;
} }
@ -527,7 +527,7 @@ jQuery(document).ready(function($) {
$feedback.html('<span style="color: #dc3232;">Please remove http:// or https://</span>').show(); $feedback.html('<span style="color: #dc3232;">Please remove http:// or https://</span>').show();
} else if (domain.indexOf('/') !== -1) { } else if (domain.indexOf('/') !== -1) {
$feedback.html('<span style="color: #dc3232;">Please remove any paths or slashes</span>').show(); $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(); $feedback.html('<span style="color: #dc3232;">Please enter a valid domain format</span>').show();
} else { } else {
$feedback.html('<span style="color: #46b450;">Domain format looks good</span>').show(); $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 // Initialize when document is ready
initializePage(); initializePage();
}); });
// Domain Mapping Dashboard Widget JavaScript // Domain Mapping Dashboard Widget JavaScript
jQuery(document).ready(function($) { jQuery(document).ready(function($) {
// 健康状态刷新按钮 // Health status refresh button
$(document).on('click', '.dm-refresh-health', function(e) { $(document).on('click', '.dm-refresh-health', function(e) {
e.preventDefault(); e.preventDefault();
@ -600,7 +601,7 @@ jQuery(document).ready(function($) {
$button.prop('disabled', true); $button.prop('disabled', true);
$healthContent.addClass('dm-loading'); $healthContent.addClass('dm-loading');
// 旋转图标 // Rotate icon
$button.find('.dashicons').addClass('dashicons-update-spin'); $button.find('.dashicons').addClass('dashicons-update-spin');
$.ajax({ $.ajax({
@ -615,7 +616,7 @@ jQuery(document).ready(function($) {
if (response.success) { if (response.success) {
$healthContent.html(response.data.html); $healthContent.html(response.data.html);
// 显示成功消息 // Show success message
var $notice = $('<div class="notice notice-success is-dismissible"><p>' + var $notice = $('<div class="notice notice-success is-dismissible"><p>' +
response.data.message + '</p></div>'); response.data.message + '</p></div>');
$('#dm_domain_status_widget .inside').prepend($notice); $('#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) { $(document).on('click', '.dm-check-all-health', function(e) {
e.preventDefault(); e.preventDefault();
@ -658,12 +659,12 @@ jQuery(document).ready(function($) {
}, },
success: function(response) { success: function(response) {
if (response.success) { if (response.success) {
// 刷新健康状态区域 // Refresh health status area
if ($('#dm-widget-health-status').length) { if ($('#dm-widget-health-status').length) {
$('#dm-widget-health-status .dm-health-content').html(response.data.html); $('#dm-widget-health-status .dm-health-content').html(response.data.html);
} }
// 显示成功消息 // Show success message
var $notice = $('<div class="notice notice-success is-dismissible"><p>' + var $notice = $('<div class="notice notice-success is-dismissible"><p>' +
response.data.message + '</p></div>'); response.data.message + '</p></div>');
$('#dm_domain_status_widget .inside').prepend($notice); $('#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')) { if ($('#dm_domain_status_widget').length && $('#dm_domain_status_widget').is(':visible')) {
// 每10分钟自动刷新一次 // Auto-refresh every 10 minutes
var autoRefreshInterval = setInterval(function() { var autoRefreshInterval = setInterval(function() {
if ($('#dm_domain_status_widget').is(':visible')) { if ($('#dm_domain_status_widget').is(':visible')) {
$('.dm-refresh-health').first().trigger('click'); $('.dm-refresh-health').first().trigger('click');
} }
}, 600000); // 10分钟 }, 600000); // 10 minutes
// 页面卸载时清除定时器 // Clear timer on page unload
$(window).on('beforeunload', function() { $(window).on('beforeunload', function() {
clearInterval(autoRefreshInterval); clearInterval(autoRefreshInterval);
}); });
} }
// 小工具配置保存 // Widget configuration save
$(document).on('submit', '#dm_domain_status_widget form', function(e) { $(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'); var showHealth = $('#dm_widget_show_health').is(':checked');
// 如果取消勾选健康状态,隐藏相关区域 // If unchecked health status, hide related areas
if (!showHealth) { if (!showHealth) {
$('#dm-widget-health-status').fadeOut(); $('#dm-widget-health-status').fadeOut();
} else { } 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() { $('.dm-domains-list a, .dm-domain-primary a').each(function() {
if (!$(this).find('.dashicons-external').length) { if (!$(this).find('.dashicons-external').length) {
$(this).append(' <span class="dashicons dashicons-external" style="font-size: 14px; vertical-align: middle;"></span>'); $(this).append(' <span class="dashicons dashicons-external" style="font-size: 14px; vertical-align: middle;"></span>');
} }
}); });
// 工具提示 // Tooltips
if ($.fn.tooltip) { if ($.fn.tooltip) {
$('#dm_domain_status_widget [title]').tooltip({ $('#dm_domain_status_widget [title]').tooltip({
position: { position: {

View file

@ -822,173 +822,205 @@ class WP_Domain_Mapping_Admin {
} }
/** /**
* AJAX handler for domain actions * AJAX handler for domain actions - IMPROVED SECURITY
* UPDATED: Support editing domain names and better conflict checking
*/ */
public function ajax_handle_actions() { 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' ) ) { if ( ! current_user_can( 'manage_network' ) ) {
wp_send_json_error( __( 'Permission denied.', 'wp-domain-mapping' ) ); wp_send_json_error( __( 'Permission denied.', 'wp-domain-mapping' ) );
} }
global $wpdb; global $wpdb;
$action = sanitize_text_field( $_POST['action_type'] ); // Sanitize and validate inputs
$domain = dm_clean_domain( sanitize_text_field( isset( $_POST['domain'] ) ? strtolower( $_POST['domain'] ) : '' ) ); $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; $blog_id = isset( $_POST['blog_id'] ) ? absint( $_POST['blog_id'] ) : 0;
$active = isset( $_POST['active'] ) ? absint( $_POST['active'] ) : 0; $active = isset( $_POST['active'] ) ? absint( $_POST['active'] ) : 0;
$orig_domain = isset( $_POST['orig_domain'] ) ? dm_clean_domain( sanitize_text_field( $_POST['orig_domain'] ) ) : ''; $orig_domain = isset( $_POST['orig_domain'] ) ? dm_clean_domain( sanitize_text_field( $_POST['orig_domain'] ) ) : '';
$current_user_id = get_current_user_id(); $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 ) { switch ( $action ) {
case 'save': case 'save':
if ( $blog_id != 0 && $blog_id != 1 ) { // Enhanced validation for save action
// Validate domain format if ( $blog_id <= 0 || $blog_id === 1 ) {
if ( ! dm_validate_domain( $domain ) ) { wp_send_json_error( __( 'Invalid site ID.', 'wp-domain-mapping' ) );
wp_send_json_error( __( 'Invalid domain format.', 'wp-domain-mapping' ) ); }
// Validate domain format
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;
if ( $domain_changed || empty( $orig_domain ) ) {
// Check if domain exists for another blog
$exists = dm_domain_exists_for_another_blog( $domain, $blog_id );
if ( $exists ) {
wp_send_json_error( sprintf(
__( 'Domain %s is already mapped to site ID %d.', 'wp-domain-mapping' ),
esc_html( $domain ),
intval( $exists->blog_id )
));
} }
}
// For editing, check if domain changed $wpdb->query( 'START TRANSACTION' );
$domain_changed = ! empty( $orig_domain ) && $orig_domain !== $domain;
if ( $domain_changed || empty( $orig_domain ) ) { try {
// Check if domain exists for another blog if ( empty( $orig_domain ) ) {
$exists = dm_domain_exists_for_another_blog( $domain, $blog_id ); // Insert new domain
$success = $wpdb->insert(
if ( $exists ) { $this->tables['domains'],
wp_send_json_error( sprintf( array(
__( 'Domain %s is already mapped to site ID %d.', 'wp-domain-mapping' ),
$domain,
$exists->blog_id
));
}
}
$wpdb->query( 'START TRANSACTION' );
try {
if ( empty( $orig_domain ) ) {
// Insert new domain
$success = $wpdb->insert(
$this->tables['domains'],
array(
'blog_id' => $blog_id,
'domain' => $domain,
'active' => $active
),
array( '%d', '%s', '%d' )
);
if ( $success ) {
// If setting as primary, reset other domains
if ( $active ) {
$wpdb->update(
$this->tables['domains'],
array( 'active' => 0 ),
array(
'blog_id' => $blog_id,
'domain !=' => $domain
),
array( '%d' ),
array( '%d', '%s' )
);
}
// Log the action
dm_log_action( 'add', $domain, $blog_id, $current_user_id );
$wpdb->query( 'COMMIT' );
wp_send_json_success( __( 'Domain added successfully.', 'wp-domain-mapping' ) );
} else {
$wpdb->query( 'ROLLBACK' );
wp_send_json_error( __( 'Failed to add domain.', 'wp-domain-mapping' ) );
}
} else {
// Update existing domain
// Prepare update data
$update_data = array(
'blog_id' => $blog_id, 'blog_id' => $blog_id,
'domain' => $domain,
'active' => $active 'active' => $active
); ),
$update_format = array( '%d', '%d' ); array( '%d', '%s', '%d' )
);
// If domain changed, update it if ( $success ) {
if ( $domain_changed ) { // If setting as primary, reset other domains
$update_data['domain'] = $domain;
$update_format[] = '%s';
}
// If setting as primary, reset other domains first
if ( $active ) { if ( $active ) {
$wpdb->update( $wpdb->update(
$this->tables['domains'], $this->tables['domains'],
array( 'active' => 0 ), array( 'active' => 0 ),
array( 'blog_id' => $blog_id ), array(
'blog_id' => $blog_id,
'domain' => array( 'NOT LIKE', $domain )
),
array( '%d' ), array( '%d' ),
array( '%d' ) array( '%d' )
); );
} }
$success = $wpdb->update( // Log the action
$this->tables['domains'], dm_log_action( 'add', $domain, $blog_id, $current_user_id );
$update_data,
array( 'domain' => $orig_domain ),
$update_format,
array( '%s' )
);
if ( $success !== false ) { $wpdb->query( 'COMMIT' );
// Log the action wp_send_json_success( __( 'Domain added successfully.', 'wp-domain-mapping' ) );
dm_log_action( 'edit', $domain, $blog_id, $current_user_id ); } else {
$wpdb->query( 'ROLLBACK' );
$wpdb->query( 'COMMIT' ); wp_send_json_error( __( 'Failed to add domain.', 'wp-domain-mapping' ) );
wp_send_json_success( __( 'Domain updated successfully.', 'wp-domain-mapping' ) ); }
} else { } else {
$wpdb->query( 'ROLLBACK' ); // Validate original domain exists
wp_send_json_error( __( 'No changes were made or update failed.', 'wp-domain-mapping' ) ); $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' ) );
}
// Update existing domain
$update_data = array(
'blog_id' => $blog_id,
'active' => $active
);
$update_format = array( '%d', '%d' );
// If domain changed, update it
if ( $domain_changed ) {
$update_data['domain'] = $domain;
$update_format[] = '%s';
}
// If setting as primary, reset other domains first
if ( $active ) {
$wpdb->update(
$this->tables['domains'],
array( 'active' => 0 ),
array( 'blog_id' => $blog_id ),
array( '%d' ),
array( '%d' )
);
}
$success = $wpdb->update(
$this->tables['domains'],
$update_data,
array( 'domain' => $orig_domain ),
$update_format,
array( '%s' )
);
if ( $success !== false ) {
// Log the action
dm_log_action( 'edit', $domain, $blog_id, $current_user_id );
$wpdb->query( 'COMMIT' );
wp_send_json_success( __( 'Domain updated successfully.', 'wp-domain-mapping' ) );
} else {
$wpdb->query( 'ROLLBACK' );
wp_send_json_error( __( 'No changes were made or update failed.', 'wp-domain-mapping' ) );
} }
} catch ( Exception $e ) {
$wpdb->query( 'ROLLBACK' );
wp_send_json_error( __( 'An error occurred while saving domain.', 'wp-domain-mapping' ) );
} }
} else { } catch ( Exception $e ) {
wp_send_json_error( __( 'Invalid site ID.', 'wp-domain-mapping' ) ); $wpdb->query( 'ROLLBACK' );
error_log( 'Domain mapping error: ' . $e->getMessage() );
wp_send_json_error( __( 'An error occurred while saving domain.', 'wp-domain-mapping' ) );
} }
break; break;
case 'delete': case 'delete':
$domains = isset( $_POST['domains'] ) ? array_map( 'sanitize_text_field', (array) $_POST['domains'] ) : array( $domain ); $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' ); $wpdb->query( 'START TRANSACTION' );
$deleted = 0; $deleted = 0;
try { try {
foreach ( $domains as $del_domain ) { 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 if ( ! $domain_info ) {
$affected_blog_id = $wpdb->get_var( $wpdb->prepare( continue; // Skip non-existent domains
"SELECT blog_id FROM {$this->tables['domains']} WHERE domain = %s", }
$del_domain
));
if ( $affected_blog_id ) { // Check if user has permission to delete this domain
// Delete the domain if ( ! current_user_can( 'manage_network' ) ) {
$result = $wpdb->delete( continue; // Skip if no permission
$this->tables['domains'], }
array( 'domain' => $del_domain ),
array( '%s' )
);
if ( $result ) { // Delete the domain
$deleted++; $result = $wpdb->delete(
$this->tables['domains'],
array( 'domain' => $del_domain ),
array( '%s' )
);
// Log the action if ( $result ) {
dm_log_action( 'delete', $del_domain, $affected_blog_id, $current_user_id ); $deleted++;
} // Log the action
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 ) { } catch ( Exception $e ) {
$wpdb->query( 'ROLLBACK' ); $wpdb->query( 'ROLLBACK' );
error_log( 'Domain mapping deletion error: ' . $e->getMessage() );
wp_send_json_error( __( 'An error occurred while deleting domains.', 'wp-domain-mapping' ) ); wp_send_json_error( __( 'An error occurred while deleting domains.', 'wp-domain-mapping' ) );
} }
break; break;
@ -1313,7 +1346,7 @@ class WP_Domain_Mapping_Admin {
if ( ! get_site_option( 'dm_ipaddress' ) && ! get_site_option( 'dm_cname' ) ) { if ( ! get_site_option( 'dm_ipaddress' ) && ! get_site_option( 'dm_cname' ) ) {
if ( dm_is_site_admin() ) { if ( dm_is_site_admin() ) {
echo wp_kses( 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() ) ) array( 'a' => array( 'href' => array() ) )
); );
} else { } else {
@ -1355,7 +1388,7 @@ class WP_Domain_Mapping_Admin {
* @return array Modified columns * @return array Modified columns
*/ */
public function add_domain_mapping_columns( $columns ) { public function add_domain_mapping_columns( $columns ) {
$columns['map'] = __( 'Mapping' ); $columns['map'] = __( 'Mapping', 'wp-domain-mapping' );
return $columns; return $columns;
} }

View file

@ -105,7 +105,7 @@ class WP_Domain_Mapping_Core {
} }
/** /**
* Create required database tables * Create required database tables - OPTIMIZED
*/ */
public function create_tables() { public function create_tables() {
global $wpdb; global $wpdb;
@ -127,7 +127,7 @@ class WP_Domain_Mapping_Core {
$created = 0; $created = 0;
$charset_collate = $wpdb->get_charset_collate(); $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'] ) { if ( $wpdb->get_var( "SHOW TABLES LIKE '{$this->tables['domains']}'" ) != $this->tables['domains'] ) {
$wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['domains']}` ( $wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['domains']}` (
`id` bigint(20) NOT NULL auto_increment, `id` bigint(20) NOT NULL auto_increment,
@ -135,24 +135,29 @@ class WP_Domain_Mapping_Core {
`domain` varchar(255) NOT NULL, `domain` varchar(255) NOT NULL,
`active` tinyint(4) default '1', `active` tinyint(4) default '1',
PRIMARY KEY (`id`), 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;" ); ) $charset_collate;" );
$created = 1; $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'] ) { if ( $wpdb->get_var( "SHOW TABLES LIKE '{$this->tables['logins']}'" ) != $this->tables['logins'] ) {
$wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['logins']}` ( $wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['logins']}` (
`id` varchar(32) NOT NULL, `id` varchar(32) NOT NULL,
`user_id` bigint(20) NOT NULL, `user_id` bigint(20) NOT NULL,
`blog_id` bigint(20) NOT NULL, `blog_id` bigint(20) NOT NULL,
`t` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `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;" ); ) $charset_collate;" );
$created = 1; $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'] ) { if ( $wpdb->get_var( "SHOW TABLES LIKE '{$this->tables['logs']}'" ) != $this->tables['logs'] ) {
$wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['logs']}` ( $wpdb->query( "CREATE TABLE IF NOT EXISTS `{$this->tables['logs']}` (
`id` bigint(20) NOT NULL auto_increment, `id` bigint(20) NOT NULL auto_increment,
@ -161,7 +166,11 @@ class WP_Domain_Mapping_Core {
`domain` varchar(255) NOT NULL, `domain` varchar(255) NOT NULL,
`blog_id` bigint(20) NOT NULL, `blog_id` bigint(20) NOT NULL,
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP, `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;" ); ) $charset_collate;" );
$created = 1; $created = 1;
} }
@ -176,7 +185,7 @@ class WP_Domain_Mapping_Core {
$tables_created = true; $tables_created = true;
} }
} }
/** /**
* Delete blog domain mappings when a blog is deleted * Delete blog domain mappings when a blog is deleted
* *
@ -472,109 +481,115 @@ class WP_Domain_Mapping_Core {
/** /**
* Handle remote login JS * Handle remote login JS
*/ */
public function remote_login_js() { public function remote_login_js() {
global $current_blog, $current_user, $wpdb; global $current_blog, $current_user, $wpdb;
if (strtotime($details->t) < (time() - 300)) { if ( 0 == get_site_option( 'dm_remote_login' ) ) {
wp_die(__('Login key expired', 'wp-domain-mapping')); return;
} }
if ( 0 == get_site_option( 'dm_remote_login' ) ) { $hash = $this->get_hash();
return; $protocol = is_ssl() ? 'https://' : 'http://';
}
$hash = $this->get_hash(); if ( $_GET['dm'] == $hash ) {
$protocol = is_ssl() ? 'https://' : 'http://'; if ( $_GET['action'] == 'load' ) {
if ( ! is_user_logged_in() ) {
exit;
}
if ( $_GET['dm'] == $hash ) { $key = md5( time() . mt_rand() );
if ( $_GET['action'] == 'load' ) {
if ( ! is_user_logged_in() ) {
exit;
}
$key = md5( time() . mt_rand() ); $wpdb->insert(
$this->tables['logins'],
array(
'id' => $key,
'user_id' => $current_user->ID,
'blog_id' => $_GET['blogid'],
't' => current_time( 'mysql' )
),
array( '%s', '%d', '%d', '%s' )
);
$wpdb->insert( $url = add_query_arg(
$this->tables['logins'], array(
array( 'action' => 'login',
'id' => $key, 'dm' => $hash,
'user_id' => $current_user->ID, 'k' => $key,
'blog_id' => $_GET['blogid'], 't' => mt_rand()
't' => current_time( 'mysql' ) ),
), $_GET['back']
array( '%s', '%d', '%d', '%s' ) );
);
$url = add_query_arg( echo "window.location = '" . esc_url( $url ) . "'";
array( exit;
'action' => 'login',
'dm' => $hash,
'k' => $key,
't' => mt_rand()
),
$_GET['back']
);
echo "window.location = '" . esc_url( $url ) . "'"; } elseif ( $_GET['action'] == 'login' ) {
exit; $details = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$this->tables['logins']} WHERE id = %s AND blog_id = %d",
$_GET['k'], $wpdb->blogid
));
} elseif ( $_GET['action'] == 'login' ) { if ( $details ) {
$details = $wpdb->get_row( $wpdb->prepare( // FIX: Add time validation that was missing
"SELECT * FROM {$this->tables['logins']} WHERE id = %s AND blog_id = %d", if ( strtotime( $details->t ) < ( time() - 300 ) ) {
$_GET['k'], $wpdb->blogid wp_die( __( 'Login key expired', 'wp-domain-mapping' ) );
)); }
if ( $details ) { if ( $details->blog_id == $wpdb->blogid ) {
if ( $details->blog_id == $wpdb->blogid ) { $wpdb->delete(
$wpdb->delete( $this->tables['logins'],
$this->tables['logins'], array( 'id' => $_GET['k'] ),
array( 'id' => $_GET['k'] ), array( '%s' )
array( '%s' ) );
);
$wpdb->query( $wpdb->prepare( $wpdb->query( $wpdb->prepare(
"DELETE FROM {$this->tables['logins']} WHERE t < %s", "DELETE FROM {$this->tables['logins']} WHERE t < %s",
date( 'Y-m-d H:i:s', time() - 120 ) date( 'Y-m-d H:i:s', time() - 120 )
)); ));
wp_set_auth_cookie( $details->user_id ); wp_set_auth_cookie( $details->user_id );
wp_redirect( remove_query_arg( wp_redirect( remove_query_arg(
array( 'dm', 'action', 'k', 't' ), array( 'dm', 'action', 'k', 't' ),
$protocol . $current_blog->domain . $_SERVER['REQUEST_URI'] $protocol . $current_blog->domain . $_SERVER['REQUEST_URI']
)); ));
exit; exit;
} else { } else {
wp_die( esc_html__( "Incorrect or out of date login key", 'wp-domain-mapping' ) ); wp_die( esc_html__( "Incorrect or out of date login key", 'wp-domain-mapping' ) );
} }
} else { } else {
wp_die( esc_html__( "Unknown login key", 'wp-domain-mapping' ) ); wp_die( esc_html__( "Unknown login key", 'wp-domain-mapping' ) );
} }
} elseif ( $_GET['action'] == 'logout' ) { } elseif ( $_GET['action'] == 'logout' ) {
$details = $wpdb->get_row( $wpdb->prepare( $details = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$this->tables['logins']} WHERE id = %s AND blog_id = %d", "SELECT * FROM {$this->tables['logins']} WHERE id = %s AND blog_id = %d",
$_GET['k'], $_GET['blogid'] $_GET['k'], $_GET['blogid']
)); ));
if ( $details ) { if ( $details ) {
$wpdb->delete( // FIX: Add time validation for logout too
$this->tables['logins'], if ( strtotime( $details->t ) < ( time() - 300 ) ) {
array( 'id' => $_GET['k'] ), wp_die( __( 'Logout key expired', 'wp-domain-mapping' ) );
array( '%s' ) }
);
$blog = get_blog_details( $_GET['blogid'] ); $wpdb->delete(
wp_clear_auth_cookie(); $this->tables['logins'],
wp_redirect( trailingslashit( $blog->siteurl ) . "wp-login.php?loggedout=true" ); array( 'id' => $_GET['k'] ),
exit; array( '%s' )
} else { );
wp_die( esc_html__( "Unknown logout key", 'wp-domain-mapping' ) );
} $blog = get_blog_details( $_GET['blogid'] );
} wp_clear_auth_cookie();
} wp_redirect( trailingslashit( $blog->siteurl ) . "wp-login.php?loggedout=true" );
} exit;
} else {
wp_die( esc_html__( "Unknown logout key", 'wp-domain-mapping' ) );
}
}
}
}
/** /**
* Add JS loader for remote login * Add JS loader for remote login

View file

@ -94,6 +94,14 @@ class WP_Domain_Mapping_Tools {
add_action( 'admin_init', array( $this, 'handle_export' ) ); 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_manual_check' ) );
add_action( 'admin_init', array( $this, 'handle_health_settings_save' ) ); 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() { public function schedule_health_check() {
if ( ! wp_next_scheduled( 'dm_domain_health_check' ) ) { // First clear existing schedules
wp_schedule_event( time(), 'daily', 'dm_domain_health_check' ); $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() { public function unschedule_health_check() {
$timestamp = wp_next_scheduled( 'dm_domain_health_check' ); // Clear main health check
if ( $timestamp ) { wp_clear_scheduled_hook( 'dm_domain_health_check' );
wp_unschedule_event( $timestamp, 'dm_domain_health_check' );
}
// Also clear any batch processing // Clear batch processing health check
$timestamp = wp_next_scheduled( 'dm_domain_health_check_batch' ); wp_clear_scheduled_hook( 'dm_domain_health_check_batch' );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, '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() { 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 // Check if health checks are enabled
if ( ! get_site_option( 'dm_health_check_enabled', true ) ) { if ( ! get_site_option( 'dm_health_check_enabled', true ) ) {
error_log( 'WP Domain Mapping: Health check is disabled, skipping' );
return; return;
} }
// Update last execution time
update_site_option( 'dm_last_health_check', current_time( 'timestamp' ) );
// Start batch processing
$this->start_health_check_batch(); $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 ); 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 // 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' ) ); 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) { if ($_FILES['csv_file']['size'] > 5 * 1024 * 1024) {
wp_send_json_error(__('File size exceeds 5MB limit.', 'wp-domain-mapping')); wp_send_json_error(__('File size exceeds 5MB limit.', 'wp-domain-mapping'));
return; return;
@ -915,7 +1024,7 @@ class WP_Domain_Mapping_Tools {
$update_existing = isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false; $update_existing = isset( $_POST['update_existing'] ) ? (bool) $_POST['update_existing'] : false;
$validate_sites = isset( $_POST['validate_sites'] ) ? (bool) $_POST['validate_sites'] : true; $validate_sites = isset( $_POST['validate_sites'] ) ? (bool) $_POST['validate_sites'] : true;
// 验证文件类型 // Validate file type
$file_type = wp_check_filetype($_FILES['csv_file']['name']); $file_type = wp_check_filetype($_FILES['csv_file']['name']);
if (!in_array($file_type['ext'], array('csv', 'txt'))) { if (!in_array($file_type['ext'], array('csv', 'txt'))) {
wp_send_json_error(__('Only CSV files are allowed.', 'wp-domain-mapping')); wp_send_json_error(__('Only CSV files are allowed.', 'wp-domain-mapping'));

View file

@ -25,7 +25,7 @@ function dm_ensure_protocol( $domain ) {
/** /**
* Clean domain name (remove protocol and trailing slash) * 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 * @param string $domain Domain name
* @return string Cleaned domain * @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 ( function_exists( 'idn_to_ascii' ) && preg_match( '/[^a-z0-9\-\.]/i', $domain ) ) {
if (defined('INTL_IDNA_VARIANT_UTS46')) { if (defined('INTL_IDNA_VARIANT_UTS46')) {
// PHP 7.2+ // 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 { } else {
// PHP < 7.2 // 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 * 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 * @param string $domain The domain
* @return bool True if valid * @return bool True if valid
*/ */
function dm_validate_domain( $domain ) { function dm_validate_domain( $domain ) {
// Basic validation - now accepts www prefix // Remove possible protocol and path
return (bool) preg_match( '/^(www\.)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$/i', $domain ); $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) { function dm_get_domains_by_blog_id_cached($blog_id) {
$cache_key = 'dm_domains_' . $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) { if (false === $domains) {
$domains = dm_get_domains_by_blog_id($blog_id); $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; return $domains;
} }
// Clear cache function // Clear cache function - IMPROVED
function dm_clear_domain_cache($blog_id) { function dm_clear_domain_cache($blog_id = null) {
wp_cache_delete('dm_domains_' . $blog_id, 'domain_mapping'); $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

View file

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Sunrise.php for WordPress Domain Mapping * Sunrise.php for WP Domain Mapping
* *
* This file must be copied to wp-content/sunrise.php * This file must be copied to wp-content/sunrise.php
* Also, you must add "define('SUNRISE', 'on');" to wp-config.php * Also, you must add "define('SUNRISE', 'on');" to wp-config.php
@ -18,16 +18,27 @@ if (!defined('MULTISITE') || !MULTISITE) {
// Enable domain mapping // Enable domain mapping
define('DOMAIN_MAPPING', 1); define('DOMAIN_MAPPING', 1);
// Check if we're on the main site already // Don't process if we're in admin and on the original domain
if (defined('COOKIE_DOMAIN') && COOKIE_DOMAIN == $_SERVER['HTTP_HOST']) { if (is_admin() && isset($_SERVER['HTTP_HOST'])) {
return; // Allow admin access from any domain - we'll handle this in the plugin itself
} }
global $wpdb, $current_blog, $current_site; global $wpdb, $current_blog, $current_site;
// Check if tables exist before proceeding
if (!$wpdb) {
return;
}
// Get domains table name // Get domains table name
$domain_mapping_table = $wpdb->base_prefix . 'domain_mapping'; $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 // Check for the current domain in the domain mapping table
$domain = sanitize_text_field($_SERVER['HTTP_HOST']); $domain = sanitize_text_field($_SERVER['HTTP_HOST']);
$blog_id = $wpdb->get_var($wpdb->prepare( $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 we found a mapped domain, override current_blog
if (!empty($blog_id)) { if (!empty($blog_id)) {
// Get the mapped blog details // 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) { if ($mapped_blog) {
// Override current_blog // Override current_blog
$current_blog = $mapped_blog; $current_blog = $mapped_blog;
// Also set the cookie domain to the current domain // Set cookie domain for the mapped domain (only if not defined in wp-config.php)
define('COOKIE_DOMAIN', $_SERVER['HTTP_HOST']); if (!defined('COOKIE_DOMAIN')) {
define('COOKIE_DOMAIN', $domain);
}
// Define the mapped domain constant // Define the mapped domain constant
define('MAPPED_DOMAIN', true); define('MAPPED_DOMAIN', true);
@ -53,12 +69,35 @@ if (!empty($blog_id)) {
// Allow other plugins to know this is a mapped domain // Allow other plugins to know this is a mapped domain
$GLOBALS['dm_domain'] = array( $GLOBALS['dm_domain'] = array(
'original' => $current_blog->domain, 'original' => $current_blog->domain,
'mapped' => $_SERVER['HTTP_HOST'] 'mapped' => $domain,
'blog_id' => $blog_id
); );
// Fix request URI for path sites // Fix request URI for path sites
if ($current_blog->path != '/' && ($current_blog->path != '/wp/' || strpos($_SERVER['REQUEST_URI'], '/wp/') === false)) { if ($current_blog->path != '/' && ($current_blog->path != '/wp/' || strpos($_SERVER['REQUEST_URI'], '/wp/') === false)) {
$current_blog->path = '/'; $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)
);
}

View file

@ -3,7 +3,7 @@
* Plugin Name: WP Domain Mapping * Plugin Name: WP Domain Mapping
* Plugin URI: https://wenpai.org/plugins/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. * 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: WPDomain.com
* Author URI: https://wpdomain.com/ * Author URI: https://wpdomain.com/
* Network: true * Network: true
@ -20,7 +20,7 @@ if ( ! defined( 'ABSPATH' ) ) {
} }
// Define plugin constants // 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_URL', plugin_dir_url( __FILE__ ) );
define( 'WP_DOMAIN_MAPPING_DIR_PATH', plugin_dir_path( __FILE__ ) ); define( 'WP_DOMAIN_MAPPING_DIR_PATH', plugin_dir_path( __FILE__ ) );
define( 'WP_DOMAIN_MAPPING_BASENAME', plugin_basename( __FILE__ ) ); define( 'WP_DOMAIN_MAPPING_BASENAME', plugin_basename( __FILE__ ) );