mirror of
https://github.com/WPMultisite/wp-multisite-dashboard.git
synced 2025-08-03 11:11:31 +08:00
v1.2.2 稳定版
首发正式版本
This commit is contained in:
parent
836b293850
commit
a8c3a0b96d
20 changed files with 5001 additions and 4432 deletions
|
@ -1,230 +1,242 @@
|
|||
jQuery(document).ready(function($) {
|
||||
'use strict';
|
||||
jQuery(document).ready(function ($) {
|
||||
"use strict";
|
||||
|
||||
const MSD_Core = {
|
||||
refreshInterval: null,
|
||||
refreshRate: 300000,
|
||||
isRefreshing: false,
|
||||
retryCount: 0,
|
||||
maxRetries: 3,
|
||||
const MSD_Core = {
|
||||
refreshInterval: null,
|
||||
refreshRate: 300000,
|
||||
isRefreshing: false,
|
||||
retryCount: 0,
|
||||
maxRetries: 3,
|
||||
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.startAutoRefresh();
|
||||
this.setupErrorHandling();
|
||||
},
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.startAutoRefresh();
|
||||
this.setupErrorHandling();
|
||||
},
|
||||
|
||||
bindEvents() {
|
||||
$(document)
|
||||
.on('click', '.msd-refresh-btn', this.handleRefreshClick.bind(this));
|
||||
bindEvents() {
|
||||
$(document).on(
|
||||
"click",
|
||||
".msd-refresh-btn",
|
||||
this.handleRefreshClick.bind(this),
|
||||
);
|
||||
|
||||
$(window).on('beforeunload', () => {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setupErrorHandling() {
|
||||
$(document).ajaxError((event, xhr, settings, error) => {
|
||||
if (settings.url && settings.url.includes('msd_')) {
|
||||
console.error('MSD Ajax Error:', error, xhr);
|
||||
this.showNotice(msdAjax.strings.error_occurred, 'error');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
startAutoRefresh() {
|
||||
this.refreshInterval = setInterval(() => {
|
||||
if (!this.isRefreshing && document.visibilityState === 'visible') {
|
||||
if (window.MSD_Widgets && window.MSD_Widgets.loadAllWidgets) {
|
||||
window.MSD_Widgets.loadAllWidgets();
|
||||
}
|
||||
}
|
||||
}, this.refreshRate);
|
||||
},
|
||||
|
||||
handleRefreshClick(e) {
|
||||
e.preventDefault();
|
||||
const $btn = $(e.currentTarget);
|
||||
const widgetType = $btn.data('widget');
|
||||
|
||||
if ($btn.hasClass('refreshing')) return;
|
||||
|
||||
$btn.addClass('refreshing').prop('disabled', true);
|
||||
|
||||
setTimeout(() => {
|
||||
$btn.removeClass('refreshing').prop('disabled', false);
|
||||
}, 2000);
|
||||
|
||||
if (widgetType && window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadWidget(widgetType);
|
||||
this.showNotice(msdAjax.strings.refresh_success, 'success', 2000);
|
||||
} else if (window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadAllWidgets();
|
||||
this.showNotice(msdAjax.strings.refresh_success, 'success', 2000);
|
||||
}
|
||||
},
|
||||
|
||||
makeAjaxRequest(action, data, successCallback, errorCallback) {
|
||||
const ajaxData = {
|
||||
action: action,
|
||||
nonce: msdAjax.nonce,
|
||||
...data
|
||||
};
|
||||
|
||||
return $.post(msdAjax.ajaxurl, ajaxData)
|
||||
.done((response) => {
|
||||
if (response.success) {
|
||||
successCallback(response);
|
||||
} else {
|
||||
errorCallback(response.data || 'Unknown error');
|
||||
}
|
||||
})
|
||||
.fail((xhr, status, error) => {
|
||||
errorCallback(error);
|
||||
});
|
||||
},
|
||||
|
||||
showNotice(message, type = 'info', duration = 5000) {
|
||||
const $notice = $(`<div class="msd-notice ${type}"><p>${this.escapeHtml(message)}</p></div>`);
|
||||
|
||||
const $container = $('.wrap h1').first();
|
||||
if ($container.length) {
|
||||
$container.after($notice);
|
||||
} else {
|
||||
$('body').prepend($notice);
|
||||
}
|
||||
|
||||
if (duration > 0) {
|
||||
setTimeout(() => {
|
||||
$notice.fadeOut(300, () => $notice.remove());
|
||||
}, duration);
|
||||
}
|
||||
|
||||
$notice.on('click', () => {
|
||||
$notice.fadeOut(300, () => $notice.remove());
|
||||
});
|
||||
},
|
||||
|
||||
formatNumber(num) {
|
||||
if (num >= 1000000) {
|
||||
return (num / 1000000).toFixed(1) + 'M';
|
||||
} else if (num >= 1000) {
|
||||
return (num / 1000).toFixed(1) + 'K';
|
||||
}
|
||||
return num.toString();
|
||||
},
|
||||
|
||||
formatTime(date) {
|
||||
return date.toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
},
|
||||
|
||||
escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
},
|
||||
|
||||
decodeHtmlEntities(text) {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.innerHTML = text;
|
||||
return textarea.value;
|
||||
},
|
||||
|
||||
truncateText(text, maxLength) {
|
||||
if (!text || text.length <= maxLength) {
|
||||
return text;
|
||||
}
|
||||
return text.substring(0, maxLength).trim() + '...';
|
||||
},
|
||||
|
||||
isValidUrl(string) {
|
||||
try {
|
||||
const url = new URL(string);
|
||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
getStorageStatusClass(status) {
|
||||
const statusMap = {
|
||||
critical: 'critical',
|
||||
warning: 'warning',
|
||||
good: '',
|
||||
default: ''
|
||||
};
|
||||
return statusMap[status] || statusMap.default;
|
||||
},
|
||||
|
||||
getDefaultFavicon() {
|
||||
return 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbGw9IiNmMGYwZjAiLz48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmaWxsPSIjOTk5IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iMC4zNWVtIj5TPC90ZXh0Pjwvc3ZnPg==';
|
||||
},
|
||||
|
||||
getDefaultAvatar() {
|
||||
return 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48Y2lyY2xlIGN4PSIyMCIgY3k9IjIwIiByPSIyMCIgZmlsbD0iI2Y2ZjdmNyIgc3Ryb2tlPSIjZGRkIi8+PGNpcmNsZSBjeD0iMjAiIGN5PSIxNSIgcj0iNiIgZmlsbD0iIzk5OSIvPjxlbGxpcHNlIGN4PSIyMCIgY3k9IjMzIiByeD0iMTAiIHJ5PSI3IiBmaWxsPSIjOTk5Ii8+PC9zdmc+';
|
||||
},
|
||||
|
||||
formatNewsDate(dateString) {
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffTime = Math.abs(now - date);
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays === 1) {
|
||||
return 'Yesterday';
|
||||
} else if (diffDays < 7) {
|
||||
return `${diffDays} days ago`;
|
||||
} else {
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
getUserStatusClass(status) {
|
||||
const statusMap = {
|
||||
'active': 'good',
|
||||
'recent': 'good',
|
||||
'inactive': 'warning',
|
||||
'very_inactive': 'critical',
|
||||
'never_logged_in': 'neutral'
|
||||
};
|
||||
return statusMap[status] || 'neutral';
|
||||
},
|
||||
|
||||
getUserStatusLabel(status) {
|
||||
const statusLabels = {
|
||||
'active': 'Active',
|
||||
'recent': 'Recent',
|
||||
'inactive': 'Inactive',
|
||||
'very_inactive': 'Very Inactive',
|
||||
'never_logged_in': 'Never Logged In'
|
||||
};
|
||||
return statusLabels[status] || 'Unknown';
|
||||
},
|
||||
|
||||
getRegistrationLabel(registration) {
|
||||
const labels = {
|
||||
'none': 'Disabled',
|
||||
'user': 'Users Only',
|
||||
'blog': 'Sites Only',
|
||||
'all': 'Users & Sites'
|
||||
};
|
||||
return labels[registration] || 'Unknown';
|
||||
$(window).on("beforeunload", () => {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval);
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
window.MSD_Core = MSD_Core;
|
||||
MSD_Core.init();
|
||||
setupErrorHandling() {
|
||||
$(document).ajaxError((event, xhr, settings, error) => {
|
||||
if (settings.url && settings.url.includes("msd_")) {
|
||||
console.error("MSD Ajax Error:", error, xhr);
|
||||
this.showNotice(msdAjax.strings.error_occurred, "error");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
$('head').append(`
|
||||
startAutoRefresh() {
|
||||
this.refreshInterval = setInterval(() => {
|
||||
if (!this.isRefreshing && document.visibilityState === "visible") {
|
||||
if (window.MSD_Widgets && window.MSD_Widgets.loadAllWidgets) {
|
||||
window.MSD_Widgets.loadAllWidgets();
|
||||
}
|
||||
}
|
||||
}, this.refreshRate);
|
||||
},
|
||||
|
||||
handleRefreshClick(e) {
|
||||
e.preventDefault();
|
||||
const $btn = $(e.currentTarget);
|
||||
const widgetType = $btn.data("widget");
|
||||
|
||||
if ($btn.hasClass("refreshing")) return;
|
||||
|
||||
$btn.addClass("refreshing").prop("disabled", true);
|
||||
|
||||
setTimeout(() => {
|
||||
$btn.removeClass("refreshing").prop("disabled", false);
|
||||
}, 2000);
|
||||
|
||||
if (widgetType && window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadWidget(widgetType);
|
||||
this.showNotice(msdAjax.strings.refresh_success, "success", 2000);
|
||||
} else if (window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadAllWidgets();
|
||||
this.showNotice(msdAjax.strings.refresh_success, "success", 2000);
|
||||
}
|
||||
},
|
||||
|
||||
makeAjaxRequest(action, data, successCallback, errorCallback) {
|
||||
const ajaxData = {
|
||||
action: action,
|
||||
nonce: msdAjax.nonce,
|
||||
...data,
|
||||
};
|
||||
|
||||
return $.post(msdAjax.ajaxurl, ajaxData)
|
||||
.done((response) => {
|
||||
if (response.success) {
|
||||
successCallback(response);
|
||||
} else {
|
||||
errorCallback(response.data || msdAjax.strings.unknown);
|
||||
}
|
||||
})
|
||||
.fail((xhr, status, error) => {
|
||||
errorCallback(error || msdAjax.strings.network_error);
|
||||
});
|
||||
},
|
||||
|
||||
showNotice(message, type = "info", duration = 5000) {
|
||||
const $notice = $(
|
||||
`<div class="msd-notice ${type}"><p>${this.escapeHtml(message)}</p></div>`,
|
||||
);
|
||||
|
||||
const $container = $(".wrap h1").first();
|
||||
if ($container.length) {
|
||||
$container.after($notice);
|
||||
} else {
|
||||
$("body").prepend($notice);
|
||||
}
|
||||
|
||||
if (duration > 0) {
|
||||
setTimeout(() => {
|
||||
$notice.fadeOut(300, () => $notice.remove());
|
||||
}, duration);
|
||||
}
|
||||
|
||||
$notice.on("click", () => {
|
||||
$notice.fadeOut(300, () => $notice.remove());
|
||||
});
|
||||
},
|
||||
|
||||
formatNumber(num) {
|
||||
if (num >= 1000000) {
|
||||
return (
|
||||
(num / 1000000).toFixed(1) + (msdAjax.strings.million_suffix || "M")
|
||||
);
|
||||
} else if (num >= 1000) {
|
||||
return (
|
||||
(num / 1000).toFixed(1) + (msdAjax.strings.thousand_suffix || "K")
|
||||
);
|
||||
}
|
||||
return num.toString();
|
||||
},
|
||||
|
||||
formatTime(date) {
|
||||
return date.toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
},
|
||||
|
||||
escapeHtml(text) {
|
||||
const div = document.createElement("div");
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
},
|
||||
|
||||
decodeHtmlEntities(text) {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.innerHTML = text;
|
||||
return textarea.value;
|
||||
},
|
||||
|
||||
truncateText(text, maxLength) {
|
||||
if (!text || text.length <= maxLength) {
|
||||
return text;
|
||||
}
|
||||
return (
|
||||
text.substring(0, maxLength).trim() +
|
||||
(msdAjax.strings.ellipsis || "...")
|
||||
);
|
||||
},
|
||||
|
||||
isValidUrl(string) {
|
||||
try {
|
||||
const url = new URL(string);
|
||||
return url.protocol === "http:" || url.protocol === "https:";
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
getStorageStatusClass(status) {
|
||||
const statusMap = {
|
||||
critical: "critical",
|
||||
warning: "warning",
|
||||
good: "",
|
||||
default: "",
|
||||
};
|
||||
return statusMap[status] || statusMap.default;
|
||||
},
|
||||
|
||||
getDefaultFavicon() {
|
||||
return "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbGw9IiNmMGYwZjAiLz48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmaWxsPSIjOTk5IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iMC4zNWVtIj5TPC90ZXh0Pjwvc3ZnPg==";
|
||||
},
|
||||
|
||||
getDefaultAvatar() {
|
||||
return "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48Y2lyY2xlIGN4PSIyMCIgY3k9IjIwIiByPSIyMCIgZmlsbD0iI2Y2ZjdmNyIgc3Ryb2tlPSIjZGRkIi8+PGNpcmNsZSBjeD0iMjAiIGN5PSIxNSIgcj0iNiIgZmlsbD0iIzk5OSIvPjxlbGxpcHNlIGN4PSIyMCIgY3k9IjMzIiByeD0iMTAiIHJ5PSI3IiBmaWxsPSIjOTk5Ii8+PC9zdmc+";
|
||||
},
|
||||
|
||||
formatNewsDate(dateString) {
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffTime = Math.abs(now - date);
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays === 1) {
|
||||
return msdAjax.strings.yesterday;
|
||||
} else if (diffDays < 7) {
|
||||
return msdAjax.strings.days_ago.replace("%d", diffDays);
|
||||
} else {
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
getUserStatusClass(status) {
|
||||
const statusMap = {
|
||||
active: "good",
|
||||
recent: "good",
|
||||
inactive: "warning",
|
||||
very_inactive: "critical",
|
||||
never_logged_in: "neutral",
|
||||
};
|
||||
return statusMap[status] || "neutral";
|
||||
},
|
||||
|
||||
getUserStatusLabel(status) {
|
||||
const statusLabels = {
|
||||
active: msdAjax.strings.active,
|
||||
recent: msdAjax.strings.recent,
|
||||
inactive: msdAjax.strings.inactive,
|
||||
very_inactive: msdAjax.strings.very_inactive,
|
||||
never_logged_in: msdAjax.strings.never_logged_in,
|
||||
};
|
||||
return statusLabels[status] || msdAjax.strings.unknown;
|
||||
},
|
||||
|
||||
getRegistrationLabel(registration) {
|
||||
const labels = {
|
||||
none: msdAjax.strings.registration_disabled || "Disabled",
|
||||
user: msdAjax.strings.registration_users_only || "Users Only",
|
||||
blog: msdAjax.strings.registration_sites_only || "Sites Only",
|
||||
all: msdAjax.strings.registration_users_sites || "Users & Sites",
|
||||
};
|
||||
return labels[registration] || msdAjax.strings.unknown;
|
||||
},
|
||||
};
|
||||
|
||||
window.MSD_Core = MSD_Core;
|
||||
MSD_Core.init();
|
||||
|
||||
$("head").append(`
|
||||
<style>
|
||||
body.modal-open { overflow: hidden; }
|
||||
.msd-refresh-btn.refreshing { opacity: 0.6; pointer-events: none; }
|
||||
|
|
|
@ -1,376 +1,448 @@
|
|||
jQuery(document).ready(function($) {
|
||||
'use strict';
|
||||
jQuery(document).ready(function ($) {
|
||||
"use strict";
|
||||
|
||||
const MSD_Modals = {
|
||||
init() {
|
||||
this.bindEvents();
|
||||
// 延迟初始化 sortable,等待页面完全加载
|
||||
$(document).ready(() => {
|
||||
setTimeout(() => {
|
||||
this.initSortable();
|
||||
}, 1000);
|
||||
const MSD_Modals = {
|
||||
init() {
|
||||
this.bindEvents();
|
||||
$(document).ready(() => {
|
||||
setTimeout(() => {
|
||||
this.initSortable();
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
|
||||
bindEvents() {
|
||||
$(document)
|
||||
.on("click", "#msd-add-link", this.addQuickLinkRow.bind(this))
|
||||
.on("click", ".msd-remove-link", this.removeQuickLinkRow.bind(this))
|
||||
.on("click", "#msd-add-news-source", this.addNewsSourceRow.bind(this))
|
||||
.on("click", ".msd-remove-source", this.removeNewsSourceRow.bind(this))
|
||||
.on(
|
||||
"click",
|
||||
".msd-modal-close, .msd-modal",
|
||||
this.handleModalClose.bind(this),
|
||||
)
|
||||
.on("click", ".msd-modal-content", function (e) {
|
||||
e.stopPropagation();
|
||||
})
|
||||
.on(
|
||||
"click",
|
||||
".msd-news-settings button",
|
||||
this.showNewsSourcesModal.bind(this),
|
||||
);
|
||||
|
||||
window.MSD = {
|
||||
showQuickLinksModal: this.showQuickLinksModal.bind(this),
|
||||
hideQuickLinksModal: this.hideQuickLinksModal.bind(this),
|
||||
saveQuickLinks: this.saveQuickLinks.bind(this),
|
||||
showNewsSourcesModal: this.showNewsSourcesModal.bind(this),
|
||||
hideNewsSourcesModal: this.hideNewsSourcesModal.bind(this),
|
||||
saveNewsSources: this.saveNewsSources.bind(this),
|
||||
showContactInfoModal: this.showContactInfoModal.bind(this),
|
||||
hideContactInfoModal: this.hideContactInfoModal.bind(this),
|
||||
saveContactInfo: this.saveContactInfo.bind(this),
|
||||
selectQRImage: this.selectQRImage.bind(this),
|
||||
removeQRCode: this.removeQRCode.bind(this),
|
||||
clearNewsCache: this.clearNewsCache.bind(this),
|
||||
};
|
||||
},
|
||||
|
||||
initSortable() {
|
||||
$(document).ready(() => {
|
||||
setTimeout(() => {
|
||||
if (
|
||||
$.ui &&
|
||||
$.ui.sortable &&
|
||||
$("#msd-sortable-links").length &&
|
||||
!$("#msd-sortable-links").hasClass("ui-sortable")
|
||||
) {
|
||||
$("#msd-sortable-links").sortable({
|
||||
tolerance: "pointer",
|
||||
cursor: "move",
|
||||
placeholder: "ui-sortable-placeholder",
|
||||
helper: function (e, ui) {
|
||||
ui.addClass("ui-sortable-helper");
|
||||
return ui;
|
||||
},
|
||||
stop: (event, ui) => {
|
||||
this.saveQuickLinksOrder();
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
},
|
||||
|
||||
bindEvents() {
|
||||
$(document)
|
||||
.on('click', '#msd-add-link', this.addQuickLinkRow.bind(this))
|
||||
.on('click', '.msd-remove-link', this.removeQuickLinkRow.bind(this))
|
||||
.on('click', '#msd-add-news-source', this.addNewsSourceRow.bind(this))
|
||||
.on('click', '.msd-remove-source', this.removeNewsSourceRow.bind(this))
|
||||
.on('click', '.msd-modal-close, .msd-modal', this.handleModalClose.bind(this))
|
||||
.on('click', '.msd-modal-content', function(e) { e.stopPropagation(); })
|
||||
.on('click', '.msd-news-settings button', this.showNewsSourcesModal.bind(this));
|
||||
saveQuickLinksOrder() {
|
||||
const order = [];
|
||||
$("#msd-sortable-links .msd-quick-link-item").each(function () {
|
||||
const index = $(this).data("index");
|
||||
if (index !== undefined) {
|
||||
order.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
window.MSD = {
|
||||
showQuickLinksModal: this.showQuickLinksModal.bind(this),
|
||||
hideQuickLinksModal: this.hideQuickLinksModal.bind(this),
|
||||
saveQuickLinks: this.saveQuickLinks.bind(this),
|
||||
showNewsSourcesModal: this.showNewsSourcesModal.bind(this),
|
||||
hideNewsSourcesModal: this.hideNewsSourcesModal.bind(this),
|
||||
saveNewsSources: this.saveNewsSources.bind(this),
|
||||
showContactInfoModal: this.showContactInfoModal.bind(this),
|
||||
hideContactInfoModal: this.hideContactInfoModal.bind(this),
|
||||
saveContactInfo: this.saveContactInfo.bind(this),
|
||||
selectQRImage: this.selectQRImage.bind(this),
|
||||
removeQRCode: this.removeQRCode.bind(this),
|
||||
clearNewsCache: this.clearNewsCache.bind(this)
|
||||
};
|
||||
},
|
||||
if (order.length > 0 && window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest(
|
||||
"msd_reorder_quick_links",
|
||||
{ order },
|
||||
() => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.save_success,
|
||||
"success",
|
||||
2000,
|
||||
);
|
||||
},
|
||||
() => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.failed_save_order,
|
||||
"error",
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
initSortable() {
|
||||
// 使用延迟初始化,确保DOM元素存在
|
||||
$(document).ready(() => {
|
||||
setTimeout(() => {
|
||||
if ($.ui && $.ui.sortable && $('#msd-sortable-links').length && !$('#msd-sortable-links').hasClass('ui-sortable')) {
|
||||
$('#msd-sortable-links').sortable({
|
||||
tolerance: 'pointer',
|
||||
cursor: 'move',
|
||||
placeholder: 'ui-sortable-placeholder',
|
||||
helper: function(e, ui) {
|
||||
ui.addClass('ui-sortable-helper');
|
||||
return ui;
|
||||
},
|
||||
stop: (event, ui) => {
|
||||
this.saveQuickLinksOrder();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
},
|
||||
handleModalClose(e) {
|
||||
if (
|
||||
e.target === e.currentTarget ||
|
||||
$(e.target).hasClass("msd-modal-close")
|
||||
) {
|
||||
this.hideQuickLinksModal();
|
||||
this.hideNewsSourcesModal();
|
||||
this.hideContactInfoModal();
|
||||
}
|
||||
},
|
||||
|
||||
saveQuickLinksOrder() {
|
||||
const order = [];
|
||||
$('#msd-sortable-links .msd-quick-link-item').each(function() {
|
||||
const index = $(this).data('index');
|
||||
if (index !== undefined) {
|
||||
order.push(index);
|
||||
}
|
||||
});
|
||||
showQuickLinksModal() {
|
||||
$("#msd-quick-links-modal").fadeIn(200);
|
||||
$("body").addClass("modal-open");
|
||||
},
|
||||
|
||||
if (order.length > 0 && window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest('msd_reorder_quick_links', { order },
|
||||
() => {
|
||||
window.MSD_Core.showNotice(msdAjax.strings.save_success, 'success', 2000);
|
||||
},
|
||||
() => {
|
||||
window.MSD_Core.showNotice('Failed to save order', 'error');
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
hideQuickLinksModal() {
|
||||
$("#msd-quick-links-modal").fadeOut(200);
|
||||
$("body").removeClass("modal-open");
|
||||
},
|
||||
|
||||
handleModalClose(e) {
|
||||
if (e.target === e.currentTarget || $(e.target).hasClass('msd-modal-close')) {
|
||||
this.hideQuickLinksModal();
|
||||
this.hideNewsSourcesModal();
|
||||
this.hideContactInfoModal();
|
||||
}
|
||||
},
|
||||
showNewsSourcesModal() {
|
||||
$("#msd-news-sources-modal").fadeIn(200);
|
||||
$("body").addClass("modal-open");
|
||||
},
|
||||
|
||||
showQuickLinksModal() {
|
||||
$('#msd-quick-links-modal').fadeIn(200);
|
||||
$('body').addClass('modal-open');
|
||||
},
|
||||
hideNewsSourcesModal() {
|
||||
$("#msd-news-sources-modal").fadeOut(200);
|
||||
$("body").removeClass("modal-open");
|
||||
},
|
||||
|
||||
hideQuickLinksModal() {
|
||||
$('#msd-quick-links-modal').fadeOut(200);
|
||||
$('body').removeClass('modal-open');
|
||||
},
|
||||
showContactInfoModal() {
|
||||
$("#msd-contact-info-modal").fadeIn(200);
|
||||
$("body").addClass("modal-open");
|
||||
},
|
||||
|
||||
showNewsSourcesModal() {
|
||||
$('#msd-news-sources-modal').fadeIn(200);
|
||||
$('body').addClass('modal-open');
|
||||
},
|
||||
hideContactInfoModal() {
|
||||
$("#msd-contact-info-modal").fadeOut(200);
|
||||
$("body").removeClass("modal-open");
|
||||
},
|
||||
|
||||
hideNewsSourcesModal() {
|
||||
$('#msd-news-sources-modal').fadeOut(200);
|
||||
$('body').removeClass('modal-open');
|
||||
},
|
||||
|
||||
showContactInfoModal() {
|
||||
$('#msd-contact-info-modal').fadeIn(200);
|
||||
$('body').addClass('modal-open');
|
||||
},
|
||||
|
||||
hideContactInfoModal() {
|
||||
$('#msd-contact-info-modal').fadeOut(200);
|
||||
$('body').removeClass('modal-open');
|
||||
},
|
||||
|
||||
addQuickLinkRow() {
|
||||
const html = `
|
||||
addQuickLinkRow() {
|
||||
const html = `
|
||||
<div class="msd-link-item">
|
||||
<div class="msd-link-row">
|
||||
<input type="text" placeholder="Link Title" class="msd-link-title" required>
|
||||
<input type="url" placeholder="https://example.com" class="msd-link-url" required>
|
||||
<input type="text" placeholder="${msdAjax.strings.link_title}" class="msd-link-title" required>
|
||||
<input type="url" placeholder="${msdAjax.strings.url_placeholder}" class="msd-link-url" required>
|
||||
</div>
|
||||
<div class="msd-link-options">
|
||||
<input type="text" placeholder="dashicons-admin-home or 🏠" class="msd-link-icon">
|
||||
<input type="text" placeholder="${msdAjax.strings.icon_placeholder}" class="msd-link-icon">
|
||||
<label class="msd-checkbox-label">
|
||||
<input type="checkbox" class="msd-link-newtab">
|
||||
Open in new tab
|
||||
${msdAjax.strings.open_new_tab}
|
||||
</label>
|
||||
<button type="button" class="msd-remove-link">Remove</button>
|
||||
<button type="button" class="msd-remove-link">${msdAjax.strings.remove}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
$('#msd-quick-links-editor').append(html);
|
||||
},
|
||||
$("#msd-quick-links-editor").append(html);
|
||||
},
|
||||
|
||||
removeQuickLinkRow(e) {
|
||||
$(e.currentTarget).closest('.msd-link-item').fadeOut(200, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
removeQuickLinkRow(e) {
|
||||
$(e.currentTarget)
|
||||
.closest(".msd-link-item")
|
||||
.fadeOut(200, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
|
||||
addNewsSourceRow() {
|
||||
const html = `
|
||||
addNewsSourceRow() {
|
||||
const html = `
|
||||
<div class="msd-news-source-item">
|
||||
<div class="msd-source-row">
|
||||
<input type="text" placeholder="Source Name" class="msd-news-name" required>
|
||||
<input type="url" placeholder="RSS Feed URL" class="msd-news-url" required>
|
||||
<input type="text" placeholder="${msdAjax.strings.source_name}" class="msd-news-name" required>
|
||||
<input type="url" placeholder="${msdAjax.strings.rss_feed_url}" class="msd-news-url" required>
|
||||
</div>
|
||||
<div class="msd-source-options">
|
||||
<label class="msd-checkbox-label">
|
||||
<input type="checkbox" class="msd-news-enabled" checked>
|
||||
Enabled
|
||||
${msdAjax.strings.enabled}
|
||||
</label>
|
||||
<button type="button" class="msd-remove-source">Remove</button>
|
||||
<button type="button" class="msd-remove-source">${msdAjax.strings.remove}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
$('#msd-news-sources-editor').append(html);
|
||||
},
|
||||
$("#msd-news-sources-editor").append(html);
|
||||
},
|
||||
|
||||
removeNewsSourceRow(e) {
|
||||
$(e.currentTarget).closest('.msd-news-source-item').fadeOut(200, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
removeNewsSourceRow(e) {
|
||||
$(e.currentTarget)
|
||||
.closest(".msd-news-source-item")
|
||||
.fadeOut(200, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
|
||||
saveQuickLinks() {
|
||||
const links = [];
|
||||
let hasErrors = false;
|
||||
saveQuickLinks() {
|
||||
const links = [];
|
||||
let hasErrors = false;
|
||||
|
||||
// Clear previous errors
|
||||
$('.msd-link-item').removeClass('error');
|
||||
$('.msd-link-url').removeClass('error');
|
||||
$(".msd-link-item").removeClass("error");
|
||||
$(".msd-link-url").removeClass("error");
|
||||
|
||||
$('.msd-link-item').each(function() {
|
||||
const $item = $(this);
|
||||
const title = $item.find('.msd-link-title').val().trim();
|
||||
const url = $item.find('.msd-link-url').val().trim();
|
||||
const icon = $item.find('.msd-link-icon').val().trim();
|
||||
const newTab = $item.find('.msd-link-newtab').is(':checked');
|
||||
$(".msd-link-item").each(function () {
|
||||
const $item = $(this);
|
||||
const title = $item.find(".msd-link-title").val().trim();
|
||||
const url = $item.find(".msd-link-url").val().trim();
|
||||
const icon = $item.find(".msd-link-icon").val().trim();
|
||||
const newTab = $item.find(".msd-link-newtab").is(":checked");
|
||||
|
||||
if (title && url) {
|
||||
if (!MSD_Modals.isValidUrl(url)) {
|
||||
$item.find('.msd-link-url').addClass('error');
|
||||
hasErrors = true;
|
||||
return;
|
||||
}
|
||||
if (title && url) {
|
||||
if (!MSD_Modals.isValidUrl(url)) {
|
||||
$item.find(".msd-link-url").addClass("error");
|
||||
hasErrors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$item.find('.msd-link-url').removeClass('error');
|
||||
links.push({ title, url, icon, new_tab: newTab });
|
||||
} else if (title || url) {
|
||||
$item.addClass('error');
|
||||
hasErrors = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasErrors) {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.showNotice('Please fill in all required fields correctly', 'error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the save button to prevent double submission
|
||||
const $saveBtn = $('.msd-modal-footer .button-primary');
|
||||
$saveBtn.prop('disabled', true).text('Saving...');
|
||||
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest('msd_save_quick_links', { links }, (response) => {
|
||||
window.MSD_Core.showNotice(response.data.message, 'success');
|
||||
this.hideQuickLinksModal();
|
||||
setTimeout(() => location.reload(), 1000);
|
||||
}, (error) => {
|
||||
window.MSD_Core.showNotice('Failed to save quick links', 'error');
|
||||
$saveBtn.prop('disabled', false).text('Save Links');
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
saveNewsSources() {
|
||||
const sources = [];
|
||||
let hasErrors = false;
|
||||
|
||||
// Clear previous errors
|
||||
$('.msd-news-source-item').removeClass('error');
|
||||
$('.msd-news-url').removeClass('error');
|
||||
|
||||
$('.msd-news-source-item').each(function() {
|
||||
const $item = $(this);
|
||||
const name = $item.find('.msd-news-name').val().trim();
|
||||
const url = $item.find('.msd-news-url').val().trim();
|
||||
const enabled = $item.find('.msd-news-enabled').is(':checked');
|
||||
|
||||
if (name && url) {
|
||||
if (!MSD_Modals.isValidUrl(url)) {
|
||||
$item.find('.msd-news-url').addClass('error');
|
||||
hasErrors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$item.find('.msd-news-url').removeClass('error');
|
||||
sources.push({ name, url, enabled });
|
||||
} else if (name || url) {
|
||||
$item.addClass('error');
|
||||
hasErrors = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasErrors) {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.showNotice('Please fill in all required fields correctly', 'error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the save button to prevent double submission
|
||||
const $saveBtn = $('#msd-news-sources-modal .button-primary');
|
||||
$saveBtn.prop('disabled', true).text('Saving...');
|
||||
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest('msd_save_news_sources', { sources }, (response) => {
|
||||
window.MSD_Core.showNotice(response.data.message, 'success');
|
||||
this.hideNewsSourcesModal();
|
||||
if (window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadWidget('custom_news');
|
||||
}
|
||||
}, (error) => {
|
||||
window.MSD_Core.showNotice('Failed to save news sources', 'error');
|
||||
$saveBtn.prop('disabled', false).text('Save News Sources');
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
saveContactInfo() {
|
||||
const contactInfo = {
|
||||
name: $('#msd-contact-name').val().trim(),
|
||||
email: $('#msd-contact-email').val().trim(),
|
||||
phone: $('#msd-contact-phone').val().trim(),
|
||||
website: $('#msd-contact-website').val().trim(),
|
||||
description: $('#msd-contact-description').val().trim(),
|
||||
qq: $('#msd-contact-qq').val().trim(),
|
||||
wechat: $('#msd-contact-wechat').val().trim(),
|
||||
whatsapp: $('#msd-contact-whatsapp').val().trim(),
|
||||
telegram: $('#msd-contact-telegram').val().trim(),
|
||||
qr_code: $('#msd-contact-qr-code').val().trim()
|
||||
};
|
||||
|
||||
if (!contactInfo.name || !contactInfo.email) {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.showNotice('Name and email are required', 'error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the save button to prevent double submission
|
||||
const $saveBtn = $('#msd-contact-info-modal .button-primary');
|
||||
$saveBtn.prop('disabled', true).text('Saving...');
|
||||
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest('msd_save_contact_info', contactInfo, (response) => {
|
||||
window.MSD_Core.showNotice(response.data.message, 'success');
|
||||
this.hideContactInfoModal();
|
||||
setTimeout(() => location.reload(), 1000);
|
||||
}, (error) => {
|
||||
window.MSD_Core.showNotice('Failed to save contact information', 'error');
|
||||
$saveBtn.prop('disabled', false).text('Save Contact Info');
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
selectQRImage() {
|
||||
if (wp && wp.media) {
|
||||
const frame = wp.media({
|
||||
title: 'Select QR Code Image',
|
||||
button: { text: 'Use Image' },
|
||||
multiple: false
|
||||
});
|
||||
|
||||
frame.on('select', function() {
|
||||
const attachment = frame.state().get('selection').first().toJSON();
|
||||
$('#msd-contact-qr-code').val(attachment.url);
|
||||
$('#msd-qr-preview img').attr('src', attachment.url);
|
||||
$('#msd-qr-preview').show();
|
||||
});
|
||||
|
||||
frame.open();
|
||||
} else {
|
||||
const url = prompt('Enter QR code image URL:');
|
||||
if (url) {
|
||||
$('#msd-contact-qr-code').val(url);
|
||||
$('#msd-qr-preview img').attr('src', url);
|
||||
$('#msd-qr-preview').show();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeQRCode() {
|
||||
$('#msd-contact-qr-code').val('');
|
||||
$('#msd-qr-preview').hide();
|
||||
},
|
||||
|
||||
clearNewsCache() {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest('msd_refresh_widget_data', { widget: 'custom_news' }, (response) => {
|
||||
window.MSD_Core.showNotice('News cache cleared successfully', 'success');
|
||||
if (window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadWidget('custom_news');
|
||||
}
|
||||
}, (error) => {
|
||||
window.MSD_Core.showNotice('Failed to clear news cache', 'error');
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
isValidUrl(string) {
|
||||
if (window.MSD_Core && window.MSD_Core.isValidUrl) {
|
||||
return window.MSD_Core.isValidUrl(string);
|
||||
}
|
||||
try {
|
||||
const url = new URL(string);
|
||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
$item.find(".msd-link-url").removeClass("error");
|
||||
links.push({ title, url, icon, new_tab: newTab });
|
||||
} else if (title || url) {
|
||||
$item.addClass("error");
|
||||
hasErrors = true;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
window.MSD_Modals = MSD_Modals;
|
||||
MSD_Modals.init();
|
||||
if (hasErrors) {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.fill_required_fields,
|
||||
"error",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const $saveBtn = $(".msd-modal-footer .button-primary");
|
||||
$saveBtn.prop("disabled", true).text(msdAjax.strings.saving);
|
||||
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest(
|
||||
"msd_save_quick_links",
|
||||
{ links },
|
||||
(response) => {
|
||||
window.MSD_Core.showNotice(response.data.message, "success");
|
||||
this.hideQuickLinksModal();
|
||||
setTimeout(() => location.reload(), 1000);
|
||||
},
|
||||
(error) => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.failed_save_links,
|
||||
"error",
|
||||
);
|
||||
$saveBtn.prop("disabled", false).text(msdAjax.strings.save_links);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
saveNewsSources() {
|
||||
const sources = [];
|
||||
let hasErrors = false;
|
||||
|
||||
$(".msd-news-source-item").removeClass("error");
|
||||
$(".msd-news-url").removeClass("error");
|
||||
|
||||
$(".msd-news-source-item").each(function () {
|
||||
const $item = $(this);
|
||||
const name = $item.find(".msd-news-name").val().trim();
|
||||
const url = $item.find(".msd-news-url").val().trim();
|
||||
const enabled = $item.find(".msd-news-enabled").is(":checked");
|
||||
|
||||
if (name && url) {
|
||||
if (!MSD_Modals.isValidUrl(url)) {
|
||||
$item.find(".msd-news-url").addClass("error");
|
||||
hasErrors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$item.find(".msd-news-url").removeClass("error");
|
||||
sources.push({ name, url, enabled });
|
||||
} else if (name || url) {
|
||||
$item.addClass("error");
|
||||
hasErrors = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasErrors) {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.fill_required_fields,
|
||||
"error",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const $saveBtn = $("#msd-news-sources-modal .button-primary");
|
||||
$saveBtn.prop("disabled", true).text(msdAjax.strings.saving);
|
||||
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest(
|
||||
"msd_save_news_sources",
|
||||
{ sources },
|
||||
(response) => {
|
||||
window.MSD_Core.showNotice(response.data.message, "success");
|
||||
this.hideNewsSourcesModal();
|
||||
if (window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadWidget("custom_news");
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.failed_save_sources,
|
||||
"error",
|
||||
);
|
||||
$saveBtn
|
||||
.prop("disabled", false)
|
||||
.text(msdAjax.strings.save_news_sources);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
saveContactInfo() {
|
||||
const contactInfo = {
|
||||
name: $("#msd-contact-name").val().trim(),
|
||||
email: $("#msd-contact-email").val().trim(),
|
||||
phone: $("#msd-contact-phone").val().trim(),
|
||||
website: $("#msd-contact-website").val().trim(),
|
||||
description: $("#msd-contact-description").val().trim(),
|
||||
qq: $("#msd-contact-qq").val().trim(),
|
||||
wechat: $("#msd-contact-wechat").val().trim(),
|
||||
whatsapp: $("#msd-contact-whatsapp").val().trim(),
|
||||
telegram: $("#msd-contact-telegram").val().trim(),
|
||||
qr_code: $("#msd-contact-qr-code").val().trim(),
|
||||
};
|
||||
|
||||
if (!contactInfo.name || !contactInfo.email) {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.name_email_required,
|
||||
"error",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const $saveBtn = $("#msd-contact-info-modal .button-primary");
|
||||
$saveBtn.prop("disabled", true).text(msdAjax.strings.saving);
|
||||
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest(
|
||||
"msd_save_contact_info",
|
||||
contactInfo,
|
||||
(response) => {
|
||||
window.MSD_Core.showNotice(response.data.message, "success");
|
||||
this.hideContactInfoModal();
|
||||
setTimeout(() => location.reload(), 1000);
|
||||
},
|
||||
(error) => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.failed_save_contact,
|
||||
"error",
|
||||
);
|
||||
$saveBtn
|
||||
.prop("disabled", false)
|
||||
.text(msdAjax.strings.save_contact_info);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
selectQRImage() {
|
||||
if (wp && wp.media) {
|
||||
const frame = wp.media({
|
||||
title: msdAjax.strings.select_qr_image,
|
||||
button: { text: msdAjax.strings.use_image },
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
frame.on("select", function () {
|
||||
const attachment = frame.state().get("selection").first().toJSON();
|
||||
$("#msd-contact-qr-code").val(attachment.url);
|
||||
$("#msd-qr-preview img").attr("src", attachment.url);
|
||||
$("#msd-qr-preview").show();
|
||||
});
|
||||
|
||||
frame.open();
|
||||
} else {
|
||||
const url = prompt(msdAjax.strings.enter_qr_url);
|
||||
if (url) {
|
||||
$("#msd-contact-qr-code").val(url);
|
||||
$("#msd-qr-preview img").attr("src", url);
|
||||
$("#msd-qr-preview").show();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeQRCode() {
|
||||
$("#msd-contact-qr-code").val("");
|
||||
$("#msd-qr-preview").hide();
|
||||
},
|
||||
|
||||
clearNewsCache() {
|
||||
if (window.MSD_Core) {
|
||||
window.MSD_Core.makeAjaxRequest(
|
||||
"msd_refresh_widget_data",
|
||||
{ widget: "custom_news" },
|
||||
(response) => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.news_cache_cleared,
|
||||
"success",
|
||||
);
|
||||
if (window.MSD_Widgets) {
|
||||
window.MSD_Widgets.loadWidget("custom_news");
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
window.MSD_Core.showNotice(
|
||||
msdAjax.strings.failed_clear_news_cache,
|
||||
"error",
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
isValidUrl(string) {
|
||||
if (window.MSD_Core && window.MSD_Core.isValidUrl) {
|
||||
return window.MSD_Core.isValidUrl(string);
|
||||
}
|
||||
try {
|
||||
const url = new URL(string);
|
||||
return url.protocol === "http:" || url.protocol === "https:";
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.MSD_Modals = MSD_Modals;
|
||||
MSD_Modals.init();
|
||||
});
|
||||
|
|
131
assets/dashboard-settings.js
Normal file
131
assets/dashboard-settings.js
Normal file
|
@ -0,0 +1,131 @@
|
|||
jQuery(document).ready(function ($) {
|
||||
"use strict";
|
||||
|
||||
window.MSD = window.MSD || {};
|
||||
|
||||
window.MSD.clearCache = function (type) {
|
||||
if (!confirm(msdAjax.strings.clear_cache_confirm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.post(
|
||||
msdAjax.ajaxurl,
|
||||
{
|
||||
action: "msd_clear_cache",
|
||||
cache_type: type,
|
||||
nonce: msdAjax.nonce,
|
||||
},
|
||||
function (response) {
|
||||
if (response.success) {
|
||||
alert(msdAjax.strings.cache_cleared);
|
||||
} else {
|
||||
alert(
|
||||
msdAjax.strings.cache_clear_failed +
|
||||
": " +
|
||||
(response.data || msdAjax.strings.unknown_error),
|
||||
);
|
||||
}
|
||||
},
|
||||
).fail(function () {
|
||||
alert(
|
||||
msdAjax.strings.cache_clear_failed +
|
||||
" " +
|
||||
msdAjax.strings.network_error_occurred,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
window.MSD.checkForUpdates = function () {
|
||||
var $status = $("#msd-update-status");
|
||||
var $button = $status.find("button");
|
||||
|
||||
$button.prop("disabled", true).text(msdAjax.strings.checking_updates);
|
||||
|
||||
$.post(
|
||||
msdAjax.ajaxurl,
|
||||
{
|
||||
action: "msd_check_plugin_update",
|
||||
nonce: msdAjax.nonce,
|
||||
},
|
||||
function (response) {
|
||||
if (response.success) {
|
||||
if (response.data.version) {
|
||||
var message = msdAjax.strings.update_available.replace(
|
||||
"{version}",
|
||||
response.data.version,
|
||||
);
|
||||
$status.html(
|
||||
'<span class="msd-update-available">' + message + "</span>",
|
||||
);
|
||||
if (response.data.details_url) {
|
||||
$status.append(
|
||||
' <a href="' +
|
||||
response.data.details_url +
|
||||
'" target="_blank">' +
|
||||
msdAjax.strings.view_details +
|
||||
"</a>",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$status.html(
|
||||
'<span class="msd-update-current">' +
|
||||
msdAjax.strings.up_to_date +
|
||||
"</span>",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$button.prop("disabled", false).text(msdAjax.strings.check_updates);
|
||||
alert(
|
||||
msdAjax.strings.update_check_failed +
|
||||
": " +
|
||||
(response.data || msdAjax.strings.unknown_error),
|
||||
);
|
||||
}
|
||||
},
|
||||
).fail(function () {
|
||||
$button.prop("disabled", false).text(msdAjax.strings.check_updates);
|
||||
alert(
|
||||
msdAjax.strings.update_check_failed +
|
||||
" " +
|
||||
msdAjax.strings.network_error_occurred,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
window.MSD.clearWidgetCache = function () {
|
||||
if (!confirm(msdAjax.strings.clear_widget_cache_confirm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.post(
|
||||
msdAjax.ajaxurl,
|
||||
{
|
||||
action: "msd_clear_widget_cache",
|
||||
nonce: msdAjax.nonce,
|
||||
},
|
||||
function (response) {
|
||||
if (response.success) {
|
||||
alert(msdAjax.strings.widget_cache_cleared);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(
|
||||
msdAjax.strings.widget_cache_clear_failed +
|
||||
": " +
|
||||
(response.data || msdAjax.strings.unknown_error),
|
||||
);
|
||||
}
|
||||
},
|
||||
).fail(function () {
|
||||
alert(
|
||||
msdAjax.strings.widget_cache_clear_failed +
|
||||
" " +
|
||||
msdAjax.strings.network_error_occurred,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
console.log(
|
||||
msdAjax.strings.msd_settings_loaded + ":",
|
||||
Object.keys(window.MSD),
|
||||
);
|
||||
});
|
File diff suppressed because it is too large
Load diff
|
@ -1,255 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WP_MSD_Admin_Template {
|
||||
|
||||
public static function render_dashboard_notice($message, $type = 'info', $dismissible = true) {
|
||||
$classes = ['notice', "notice-{$type}"];
|
||||
|
||||
if ($dismissible) {
|
||||
$classes[] = 'is-dismissible';
|
||||
}
|
||||
|
||||
$class_string = implode(' ', $classes);
|
||||
|
||||
echo "<div class=\"{$class_string}\">";
|
||||
echo "<p>" . esc_html($message) . "</p>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public static function render_widget_header($title, $widget_id = null, $show_refresh = true) {
|
||||
echo '<div class="msd-widget-header">';
|
||||
|
||||
if ($show_refresh && $widget_id) {
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="' . esc_attr($widget_id) . '">↻</button>';
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
echo '<h3 class="msd-widget-title">' . esc_html($title) . '</h3>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function render_loading_state($message = null) {
|
||||
$message = $message ?: __('Loading...', 'wp-multisite-dashboard');
|
||||
|
||||
echo '<div class="msd-loading">';
|
||||
echo '<span class="msd-spinner"></span>';
|
||||
echo esc_html($message);
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function render_empty_state($message, $action_text = null, $action_url = null) {
|
||||
echo '<div class="msd-empty-state">';
|
||||
echo '<p>' . esc_html($message) . '</p>';
|
||||
|
||||
if ($action_text && $action_url) {
|
||||
echo '<a href="' . esc_url($action_url) . '" class="button button-primary">' . esc_html($action_text) . '</a>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function render_error_state($message, $retry_action = null) {
|
||||
echo '<div class="msd-error-state">';
|
||||
echo '<p>' . esc_html($message) . '</p>';
|
||||
|
||||
if ($retry_action) {
|
||||
echo '<button class="button msd-retry-btn" onclick="' . esc_attr($retry_action) . '">Try Again</button>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function get_priority_badge($priority) {
|
||||
$badges = [
|
||||
'low' => ['Low Priority', 'msd-priority-low'],
|
||||
'medium' => ['Medium Priority', 'msd-priority-medium'],
|
||||
'high' => ['High Priority', 'msd-priority-high']
|
||||
];
|
||||
|
||||
if (!isset($badges[$priority])) {
|
||||
$priority = 'medium';
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<span class="msd-priority-badge %s">%s</span>',
|
||||
esc_attr($badges[$priority][1]),
|
||||
esc_html($badges[$priority][0])
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_status_badge($status, $label = null) {
|
||||
$badges = [
|
||||
'active' => ['Active', 'msd-status-good'],
|
||||
'inactive' => ['Inactive', 'msd-status-warning'],
|
||||
'critical' => ['Critical', 'msd-status-critical'],
|
||||
'warning' => ['Warning', 'msd-status-warning'],
|
||||
'good' => ['Good', 'msd-status-good'],
|
||||
'neutral' => ['Neutral', 'msd-status-neutral']
|
||||
];
|
||||
|
||||
if (!isset($badges[$status])) {
|
||||
$status = 'neutral';
|
||||
}
|
||||
|
||||
$display_label = $label ?: $badges[$status][0];
|
||||
|
||||
return sprintf(
|
||||
'<span class="msd-status-badge %s">%s</span>',
|
||||
esc_attr($badges[$status][1]),
|
||||
esc_html($display_label)
|
||||
);
|
||||
}
|
||||
|
||||
public static function format_file_size($bytes) {
|
||||
if ($bytes >= 1073741824) {
|
||||
return number_format($bytes / 1073741824, 2) . ' GB';
|
||||
} elseif ($bytes >= 1048576) {
|
||||
return number_format($bytes / 1048576, 2) . ' MB';
|
||||
} elseif ($bytes >= 1024) {
|
||||
return number_format($bytes / 1024, 2) . ' KB';
|
||||
} else {
|
||||
return $bytes . ' bytes';
|
||||
}
|
||||
}
|
||||
|
||||
public static function format_time_ago($timestamp) {
|
||||
if (empty($timestamp)) {
|
||||
return __('Never', 'wp-multisite-dashboard');
|
||||
}
|
||||
|
||||
if (is_string($timestamp)) {
|
||||
$timestamp = strtotime($timestamp);
|
||||
}
|
||||
|
||||
if (!$timestamp) {
|
||||
return __('Unknown', 'wp-multisite-dashboard');
|
||||
}
|
||||
|
||||
return human_time_diff($timestamp) . ' ago';
|
||||
}
|
||||
|
||||
public static function render_progress_bar($percentage, $label = null, $status = 'good') {
|
||||
$percentage = max(0, min(100, intval($percentage)));
|
||||
$status_class = "msd-progress-{$status}";
|
||||
|
||||
echo '<div class="msd-progress-container">';
|
||||
|
||||
if ($label) {
|
||||
echo '<div class="msd-progress-label">' . esc_html($label) . '</div>';
|
||||
}
|
||||
|
||||
echo '<div class="msd-progress-bar">';
|
||||
echo '<div class="msd-progress-fill ' . esc_attr($status_class) . '" style="width: ' . $percentage . '%"></div>';
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="msd-progress-text">' . $percentage . '%</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function render_data_table($headers, $rows, $empty_message = null) {
|
||||
if (empty($rows)) {
|
||||
if ($empty_message) {
|
||||
self::render_empty_state($empty_message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="msd-data-table-wrapper">';
|
||||
echo '<table class="msd-data-table">';
|
||||
|
||||
if (!empty($headers)) {
|
||||
echo '<thead><tr>';
|
||||
foreach ($headers as $header) {
|
||||
echo '<th>' . esc_html($header) . '</th>';
|
||||
}
|
||||
echo '</tr></thead>';
|
||||
}
|
||||
|
||||
echo '<tbody>';
|
||||
foreach ($rows as $row) {
|
||||
echo '<tr>';
|
||||
foreach ($row as $cell) {
|
||||
echo '<td>' . $cell . '</td>';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody>';
|
||||
|
||||
echo '</table>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function render_action_buttons($actions) {
|
||||
if (empty($actions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="msd-action-buttons">';
|
||||
|
||||
foreach ($actions as $action) {
|
||||
$class = 'button ' . ($action['primary'] ?? false ? 'button-primary' : 'button-secondary');
|
||||
$attributes = '';
|
||||
|
||||
if (!empty($action['attributes'])) {
|
||||
foreach ($action['attributes'] as $attr => $value) {
|
||||
$attributes .= ' ' . esc_attr($attr) . '="' . esc_attr($value) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($action['url'])) {
|
||||
echo '<a href="' . esc_url($action['url']) . '" class="' . esc_attr($class) . '"' . $attributes . '>';
|
||||
echo esc_html($action['text']);
|
||||
echo '</a>';
|
||||
} else {
|
||||
echo '<button type="button" class="' . esc_attr($class) . '"' . $attributes . '>';
|
||||
echo esc_html($action['text']);
|
||||
echo '</button>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function sanitize_widget_data($data) {
|
||||
if (is_array($data)) {
|
||||
return array_map([self::class, 'sanitize_widget_data'], $data);
|
||||
}
|
||||
|
||||
if (is_string($data)) {
|
||||
return sanitize_text_field($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function validate_nonce($nonce, $action) {
|
||||
return wp_verify_nonce($nonce, $action);
|
||||
}
|
||||
|
||||
public static function can_manage_network() {
|
||||
return current_user_can('manage_network');
|
||||
}
|
||||
|
||||
public static function get_current_screen_id() {
|
||||
$screen = get_current_screen();
|
||||
return $screen ? $screen->id : '';
|
||||
}
|
||||
|
||||
public static function is_network_admin_page($page_slug = null) {
|
||||
if (!is_network_admin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($page_slug) {
|
||||
return isset($_GET['page']) && $_GET['page'] === $page_slug;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,333 +1,405 @@
|
|||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
}
|
||||
|
||||
class WP_MSD_Admin_Interface {
|
||||
|
||||
public function __construct() {
|
||||
add_action('admin_footer', [$this, 'render_modals']);
|
||||
class WP_MSD_Admin_Interface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
add_action("admin_footer", [$this, "render_modals"]);
|
||||
}
|
||||
|
||||
public function render_modals() {
|
||||
public function render_modals()
|
||||
{
|
||||
$screen = get_current_screen();
|
||||
if ($screen && $screen->id === 'dashboard-network') {
|
||||
include_once WP_MSD_PLUGIN_DIR . 'templates/admin-modals.php';
|
||||
if ($screen && $screen->id === "dashboard-network") {
|
||||
include_once WP_MSD_PLUGIN_DIR . "templates/admin-modals.php";
|
||||
}
|
||||
}
|
||||
|
||||
public function add_network_widgets() {
|
||||
public function add_network_widgets()
|
||||
{
|
||||
$plugin_core = WP_MSD_Plugin_Core::get_instance();
|
||||
$enabled_widgets = $plugin_core->get_enabled_widgets();
|
||||
|
||||
$widgets = [
|
||||
'msd_network_overview' => ['Network Overview', 'render_network_overview_widget'],
|
||||
'msd_quick_site_management' => ['Quick Site Management', 'render_quick_site_widget'],
|
||||
'msd_storage_performance' => ['Storage Usage', 'render_storage_performance_widget'],
|
||||
'msd_server_info' => ['Server Information', 'render_server_info_widget'],
|
||||
'msd_quick_links' => ['Quick Links', 'render_quick_links_widget'],
|
||||
'msd_version_info' => ['Version Information', 'render_version_info_widget'],
|
||||
'msd_custom_news' => ['Network News', 'render_custom_news_widget'],
|
||||
'msd_user_management' => ['User Management', 'render_user_management_widget'],
|
||||
'msd_contact_info' => ['Contact Information', 'render_contact_info_widget'],
|
||||
'msd_last_edits' => ['Recent Network Activity', 'render_last_edits_widget'],
|
||||
'msd_todo_widget' => ['Todo List', 'render_todo_widget']
|
||||
"msd_network_overview" => [
|
||||
__("Network Overview", "wp-multisite-dashboard"),
|
||||
"render_network_overview_widget",
|
||||
],
|
||||
"msd_quick_site_management" => [
|
||||
__("Quick Site Management", "wp-multisite-dashboard"),
|
||||
"render_quick_site_widget",
|
||||
],
|
||||
"msd_storage_performance" => [
|
||||
__("Storage Usage", "wp-multisite-dashboard"),
|
||||
"render_storage_performance_widget",
|
||||
],
|
||||
"msd_server_info" => [
|
||||
__("Server Information", "wp-multisite-dashboard"),
|
||||
"render_server_info_widget",
|
||||
],
|
||||
"msd_quick_links" => [
|
||||
__("Quick Links", "wp-multisite-dashboard"),
|
||||
"render_quick_links_widget",
|
||||
],
|
||||
"msd_version_info" => [
|
||||
__("Version Information", "wp-multisite-dashboard"),
|
||||
"render_version_info_widget",
|
||||
],
|
||||
"msd_custom_news" => [
|
||||
__("Network News", "wp-multisite-dashboard"),
|
||||
"render_custom_news_widget",
|
||||
],
|
||||
"msd_user_management" => [
|
||||
__("User Management", "wp-multisite-dashboard"),
|
||||
"render_user_management_widget",
|
||||
],
|
||||
"msd_contact_info" => [
|
||||
__("Contact Information", "wp-multisite-dashboard"),
|
||||
"render_contact_info_widget",
|
||||
],
|
||||
"msd_last_edits" => [
|
||||
__("Recent Network Activity", "wp-multisite-dashboard"),
|
||||
"render_last_edits_widget",
|
||||
],
|
||||
"msd_todo_widget" => [
|
||||
__("Todo List", "wp-multisite-dashboard"),
|
||||
"render_todo_widget",
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($widgets as $widget_id => $widget_data) {
|
||||
if (!empty($enabled_widgets[$widget_id])) {
|
||||
wp_add_dashboard_widget(
|
||||
$widget_id,
|
||||
$widget_data[0],
|
||||
[$this, $widget_data[1]]
|
||||
);
|
||||
wp_add_dashboard_widget($widget_id, $widget_data[0], [
|
||||
$this,
|
||||
$widget_data[1],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function render_network_overview_widget() {
|
||||
public function render_network_overview_widget()
|
||||
{
|
||||
echo '<div id="msd-network-overview" class="msd-widget-content" data-widget="network_overview">';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_quick_site_widget() {
|
||||
public function render_quick_site_widget()
|
||||
{
|
||||
echo '<div id="msd-quick-sites" class="msd-widget-content" data-widget="site_list">';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_storage_performance_widget() {
|
||||
public function render_storage_performance_widget()
|
||||
{
|
||||
echo '<div id="msd-storage-performance" class="msd-widget-content" data-widget="storage_data">';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_server_info_widget() {
|
||||
public function render_server_info_widget()
|
||||
{
|
||||
echo '<div id="msd-server-info" class="msd-widget-content" data-widget="server_info">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="server_info">↻</button>';
|
||||
echo '<button class="msd-refresh-btn" title="' .
|
||||
esc_attr__("Refresh", "wp-multisite-dashboard") .
|
||||
'" data-widget="server_info">↻</button>';
|
||||
$this->render_server_info_content();
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
private function render_server_info_content() {
|
||||
private function render_server_info_content()
|
||||
{
|
||||
global $wpdb, $wp_version;
|
||||
|
||||
$data = [
|
||||
'PHP Version' => phpversion(),
|
||||
'MySQL Version' => $wpdb->db_version(),
|
||||
'Server Software' => $_SERVER["SERVER_SOFTWARE"] ?? 'Unknown',
|
||||
'Server Time' => current_time('Y-m-d H:i:s'),
|
||||
'Memory Limit' => ini_get('memory_limit'),
|
||||
'Max Upload Size' => size_format(wp_max_upload_size()),
|
||||
__("PHP Version", "wp-multisite-dashboard") => phpversion(),
|
||||
__(
|
||||
"MySQL Version",
|
||||
"wp-multisite-dashboard"
|
||||
) => $wpdb->db_version(),
|
||||
__("Server Software", "wp-multisite-dashboard") =>
|
||||
$_SERVER["SERVER_SOFTWARE"] ??
|
||||
__("Unknown", "wp-multisite-dashboard"),
|
||||
__("Server Time", "wp-multisite-dashboard") => current_time(
|
||||
"Y-m-d H:i:s"
|
||||
),
|
||||
__("Memory Limit", "wp-multisite-dashboard") => ini_get(
|
||||
"memory_limit"
|
||||
),
|
||||
__("Max Upload Size", "wp-multisite-dashboard") => size_format(
|
||||
wp_max_upload_size()
|
||||
),
|
||||
];
|
||||
|
||||
$icons = [
|
||||
'PHP Version' => 'dashicons-editor-code',
|
||||
'MySQL Version' => 'dashicons-database',
|
||||
'Server Software' => 'dashicons-admin-tools',
|
||||
'Server Time' => 'dashicons-clock',
|
||||
'Memory Limit' => 'dashicons-performance',
|
||||
'Max Upload Size' => 'dashicons-upload',
|
||||
__(
|
||||
"PHP Version",
|
||||
"wp-multisite-dashboard"
|
||||
) => "dashicons-editor-code",
|
||||
__(
|
||||
"MySQL Version",
|
||||
"wp-multisite-dashboard"
|
||||
) => "dashicons-database",
|
||||
__(
|
||||
"Server Software",
|
||||
"wp-multisite-dashboard"
|
||||
) => "dashicons-admin-tools",
|
||||
__("Server Time", "wp-multisite-dashboard") => "dashicons-clock",
|
||||
__(
|
||||
"Memory Limit",
|
||||
"wp-multisite-dashboard"
|
||||
) => "dashicons-performance",
|
||||
__(
|
||||
"Max Upload Size",
|
||||
"wp-multisite-dashboard"
|
||||
) => "dashicons-upload",
|
||||
];
|
||||
|
||||
echo '<div class="msd-server-specs">';
|
||||
foreach ($data as $label => $value) {
|
||||
$icon = $icons[$label] ?? 'dashicons-info';
|
||||
$icon = $icons[$label] ?? "dashicons-info";
|
||||
echo '<div class="msd-spec-item">';
|
||||
echo '<span class="msd-spec-icon dashicons ' . esc_attr($icon) . '"></span>';
|
||||
echo '<span class="msd-spec-label">' . esc_html($label) . '</span>';
|
||||
echo '<span class="msd-spec-value">' . esc_html($value) . '</span>';
|
||||
echo '</div>';
|
||||
echo '<span class="msd-spec-icon dashicons ' .
|
||||
esc_attr($icon) .
|
||||
'"></span>';
|
||||
echo '<span class="msd-spec-label">' . esc_html($label) . "</span>";
|
||||
echo '<span class="msd-spec-value">' . esc_html($value) . "</span>";
|
||||
echo "</div>";
|
||||
}
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_version_info_widget() {
|
||||
public function render_version_info_widget()
|
||||
{
|
||||
echo '<div id="msd-version-info" class="msd-widget-content" data-widget="version_info">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="version_info">↻</button>';
|
||||
$this->render_version_info_content();
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
private function render_version_info_content() {
|
||||
$plugin_data = get_plugin_data(WP_MSD_PLUGIN_DIR . 'wp-multisite-dashboard.php');
|
||||
global $wpdb;
|
||||
|
||||
echo '<div class="msd-version-header">';
|
||||
echo '<h3><span class="dashicons dashicons-admin-multisite"></span> ' . esc_html($plugin_data['Name']) . '</h3>';
|
||||
echo '<div class="msd-version-actions">';
|
||||
echo '<a href="https://wpmultisite.com/document/wp-multisite-dashboard" target="_blank" class="msd-help-btn msd-help-docs" title="Documentation">';
|
||||
echo '<span class="dashicons dashicons-book"></span>';
|
||||
echo '</a>';
|
||||
echo '<a href="https://wpmultisite.com/support/" target="_blank" class="msd-help-btn msd-help-support" title="Support">';
|
||||
echo '<span class="dashicons dashicons-admin-comments"></span>';
|
||||
echo '</a>';
|
||||
echo '<a href="https://github.com/wpmultisite/wp-multisite-dashboard" target="_blank" class="msd-help-btn msd-help-github" title="GitHub">';
|
||||
echo '<span class="dashicons dashicons-admin-links"></span>';
|
||||
echo '</a>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
|
||||
$plugin_core = WP_MSD_Plugin_Core::get_instance();
|
||||
$update_checker = $plugin_core->get_update_checker();
|
||||
$update_available = false;
|
||||
|
||||
if ($update_checker) {
|
||||
$update = $update_checker->checkForUpdates();
|
||||
if ($update && version_compare($update->version, WP_MSD_VERSION, '>')) {
|
||||
$update_available = [
|
||||
'version' => $update->version,
|
||||
'details_url' => $update->details_url ?? '#'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($update_available) {
|
||||
echo '<div class="msd-update-notice">';
|
||||
echo '<span class="dashicons dashicons-update"></span>';
|
||||
echo '<span>' . sprintf(__('Version %s available! ', 'wp-multisite-dashboard'), esc_html($update_available['version'])) . '</span>';
|
||||
echo '<a href="' . esc_url($update_available['details_url']) . '" target="_blank" class="msd-update-link">' . __('View Details', 'wp-multisite-dashboard') . '</a>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '<div class="msd-version-specs">';
|
||||
|
||||
echo '<div class="msd-version-item">';
|
||||
echo '<span class="msd-version-icon dashicons dashicons-tag"></span>';
|
||||
echo '<span class="msd-version-label">Plugin Version</span>';
|
||||
echo '<span class="msd-version-value">' . esc_html($plugin_data['Version']) . '</span>';
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="msd-version-item">';
|
||||
echo '<span class="msd-version-icon dashicons dashicons-admin-links"></span>';
|
||||
echo '<span class="msd-version-label">Author URI</span>';
|
||||
echo '<span class="msd-version-value"><a href="' . esc_url($plugin_data['AuthorURI']) . '" target="_blank">' . esc_html($plugin_data['AuthorURI']) . '</a></span>';
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="msd-version-item">';
|
||||
echo '<span class="msd-version-icon dashicons dashicons-editor-code"></span>';
|
||||
echo '<span class="msd-version-label">Required PHP</span>';
|
||||
echo '<span class="msd-version-value msd-status-good">' . esc_html($plugin_data['RequiresPHP']) . '</span>';
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="msd-version-item">';
|
||||
echo '<span class="msd-version-icon dashicons dashicons-database"></span>';
|
||||
echo '<span class="msd-version-label">Database Tables</span>';
|
||||
$activity_table = $wpdb->base_prefix . 'msd_activity_log';
|
||||
$activity_exists = $wpdb->get_var("SHOW TABLES LIKE '{$activity_table}'") === $activity_table;
|
||||
if ($activity_exists) {
|
||||
echo '<span class="msd-version-value msd-db-status-good">✓ Activity table created</span>';
|
||||
} else {
|
||||
echo '<span class="msd-version-value msd-db-status-warning">⚠ Activity table missing</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public function render_custom_news_widget() {
|
||||
public function render_custom_news_widget()
|
||||
{
|
||||
echo '<div id="msd-custom-news" class="msd-widget-content" data-widget="custom_news">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="custom_news">↻</button>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_user_management_widget() {
|
||||
public function render_user_management_widget()
|
||||
{
|
||||
echo '<div id="msd-user-management" class="msd-widget-content" data-widget="user_management">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="user_management">↻</button>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_contact_info_widget() {
|
||||
public function render_contact_info_widget()
|
||||
{
|
||||
echo '<div id="msd-contact-info" class="msd-widget-content" data-widget="contact_info">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="contact_info">↻</button>';
|
||||
echo '<button class="msd-refresh-btn" title="' .
|
||||
esc_attr__("Refresh", "wp-multisite-dashboard") .
|
||||
'" data-widget="contact_info">↻</button>';
|
||||
$this->render_contact_info_content();
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
private function render_contact_info_content() {
|
||||
$contact_info = get_site_option('msd_contact_info', [
|
||||
'name' => get_network_option(null, 'site_name'),
|
||||
'email' => get_network_option(null, 'admin_email'),
|
||||
'phone' => '',
|
||||
'website' => network_home_url(),
|
||||
'description' => 'Network Administrator Contact Information',
|
||||
'qq' => '',
|
||||
'wechat' => '',
|
||||
'whatsapp' => '',
|
||||
'telegram' => '',
|
||||
'qr_code' => ''
|
||||
private function render_contact_info_content()
|
||||
{
|
||||
$contact_info = get_site_option("msd_contact_info", [
|
||||
"name" => get_network_option(null, "site_name"),
|
||||
"email" => get_network_option(null, "admin_email"),
|
||||
"phone" => "",
|
||||
"website" => network_home_url(),
|
||||
"description" => __(
|
||||
"Network Administrator Contact Information",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"qq" => "",
|
||||
"wechat" => "",
|
||||
"whatsapp" => "",
|
||||
"telegram" => "",
|
||||
"qr_code" => "",
|
||||
]);
|
||||
|
||||
echo '<div class="msd-contact-card">';
|
||||
echo '<div class="msd-contact-header">';
|
||||
echo '<h3><span class="dashicons dashicons-coffee"></span> ' . esc_html($contact_info['name']) . '</h3>';
|
||||
echo '</div>';
|
||||
echo '<h3><span class="dashicons dashicons-coffee"></span> ' .
|
||||
esc_html($contact_info["name"]) .
|
||||
"</h3>";
|
||||
echo "</div>";
|
||||
|
||||
echo '<div class="msd-contact-details">';
|
||||
|
||||
if (!empty($contact_info['description'])) {
|
||||
echo '<p class="msd-contact-description">' . esc_html($contact_info['description']) . '</p>';
|
||||
if (!empty($contact_info["description"])) {
|
||||
echo '<p class="msd-contact-description">' .
|
||||
esc_html($contact_info["description"]) .
|
||||
"</p>";
|
||||
}
|
||||
|
||||
echo '<div class="msd-contact-item">';
|
||||
echo '<span class="dashicons dashicons-email"></span>';
|
||||
echo '<a href="mailto:' . esc_attr($contact_info['email']) . '">' . esc_html($contact_info['email']) . '</a>';
|
||||
echo '</div>';
|
||||
echo '<a href="mailto:' .
|
||||
esc_attr($contact_info["email"]) .
|
||||
'">' .
|
||||
esc_html($contact_info["email"]) .
|
||||
"</a>";
|
||||
echo "</div>";
|
||||
|
||||
if (!empty($contact_info['phone'])) {
|
||||
if (!empty($contact_info["phone"])) {
|
||||
echo '<div class="msd-contact-item">';
|
||||
echo '<span class="dashicons dashicons-phone"></span>';
|
||||
echo '<a href="tel:' . esc_attr($contact_info['phone']) . '">' . esc_html($contact_info['phone']) . '</a>';
|
||||
echo '</div>';
|
||||
echo '<a href="tel:' .
|
||||
esc_attr($contact_info["phone"]) .
|
||||
'">' .
|
||||
esc_html($contact_info["phone"]) .
|
||||
"</a>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
echo '<div class="msd-contact-item">';
|
||||
echo '<span class="dashicons dashicons-admin-links"></span>';
|
||||
echo '<a href="' . esc_url($contact_info['website']) . '" target="_blank">' . esc_html($contact_info['website']) . '</a>';
|
||||
echo '</div>';
|
||||
echo '<a href="' .
|
||||
esc_url($contact_info["website"]) .
|
||||
'" target="_blank">' .
|
||||
esc_html($contact_info["website"]) .
|
||||
"</a>";
|
||||
echo "</div>";
|
||||
|
||||
$im_fields = [
|
||||
'qq' => ['QQ', 'dashicons-admin-users'],
|
||||
'wechat' => ['WeChat', 'dashicons-format-chat'],
|
||||
'whatsapp' => ['WhatsApp', 'dashicons-smartphone'],
|
||||
'telegram' => ['Telegram', 'dashicons-email-alt']
|
||||
"qq" => ["QQ", "dashicons-admin-users"],
|
||||
"wechat" => [
|
||||
__("WeChat", "wp-multisite-dashboard"),
|
||||
"dashicons-format-chat",
|
||||
],
|
||||
"whatsapp" => [
|
||||
__("WhatsApp", "wp-multisite-dashboard"),
|
||||
"dashicons-smartphone",
|
||||
],
|
||||
"telegram" => [
|
||||
__("Telegram", "wp-multisite-dashboard"),
|
||||
"dashicons-email-alt",
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($im_fields as $field => $data) {
|
||||
if (!empty($contact_info[$field])) {
|
||||
echo '<div class="msd-contact-item">';
|
||||
echo '<span class="dashicons ' . $data[1] . '"></span>';
|
||||
echo '<span>' . $data[0] . ': ' . esc_html($contact_info[$field]) . '</span>';
|
||||
echo '</div>';
|
||||
echo "<span>" .
|
||||
esc_html($data[0]) .
|
||||
": " .
|
||||
esc_html($contact_info[$field]) .
|
||||
"</span>";
|
||||
echo "</div>";
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($contact_info['qr_code'])) {
|
||||
if (!empty($contact_info["qr_code"])) {
|
||||
echo '<div class="msd-contact-qr">';
|
||||
echo '<img src="' . esc_url($contact_info['qr_code']) . '" alt="QR Code" class="msd-qr-image">';
|
||||
echo '</div>';
|
||||
echo '<img src="' .
|
||||
esc_url($contact_info["qr_code"]) .
|
||||
'" alt="' .
|
||||
esc_attr__("QR Code", "wp-multisite-dashboard") .
|
||||
'" class="msd-qr-image">';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
|
||||
echo '<div class="msd-contact-actions">';
|
||||
echo '<button class="button button-small" onclick="MSD.showContactInfoModal()">' . __('Edit Contact Info', 'wp-multisite-dashboard') . '</button>';
|
||||
echo '</div>';
|
||||
echo '<button class="button button-small" onclick="MSD.showContactInfoModal()">' .
|
||||
__("Edit Contact Info", "wp-multisite-dashboard") .
|
||||
"</button>";
|
||||
echo "</div>";
|
||||
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_last_edits_widget() {
|
||||
public function render_last_edits_widget()
|
||||
{
|
||||
echo '<div id="msd-last-edits" class="msd-widget-content" data-widget="last_edits">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="last_edits">↻</button>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_quick_links_widget() {
|
||||
$quick_links = get_site_option('msd_quick_links', []);
|
||||
public function render_quick_links_widget()
|
||||
{
|
||||
$quick_links = get_site_option("msd_quick_links", []);
|
||||
|
||||
echo '<div id="msd-quick-links" class="msd-widget-content">';
|
||||
|
||||
if (empty($quick_links)) {
|
||||
echo '<div class="msd-empty-state">';
|
||||
echo '<p>' . __('No quick links configured.', 'wp-multisite-dashboard') . '</p>';
|
||||
echo '<button class="button button-primary button-small" onclick="MSD.showQuickLinksModal()">' . __('Add Links', 'wp-multisite-dashboard') . '</button>';
|
||||
echo '</div>';
|
||||
echo "<p>" .
|
||||
__("No quick links configured.", "wp-multisite-dashboard") .
|
||||
"</p>";
|
||||
echo '<button class="button button-primary button-small" onclick="MSD.showQuickLinksModal()">' .
|
||||
__("Add Links", "wp-multisite-dashboard") .
|
||||
"</button>";
|
||||
echo "</div>";
|
||||
} else {
|
||||
echo '<div class="msd-quick-links-grid" id="msd-sortable-links">';
|
||||
foreach ($quick_links as $index => $link) {
|
||||
$target = !empty($link['new_tab']) ? '_blank' : '_self';
|
||||
echo '<a href="' . esc_url($link['url']) . '" target="' . $target . '" class="msd-quick-link-item" data-index="' . $index . '">';
|
||||
$target = !empty($link["new_tab"]) ? "_blank" : "_self";
|
||||
echo '<a href="' .
|
||||
esc_url($link["url"]) .
|
||||
'" target="' .
|
||||
$target .
|
||||
'" class="msd-quick-link-item" data-index="' .
|
||||
$index .
|
||||
'">';
|
||||
|
||||
if (!empty($link['icon'])) {
|
||||
if (strpos($link['icon'], 'dashicons-') === 0) {
|
||||
echo '<span class="dashicons ' . esc_attr($link['icon']) . '"></span>';
|
||||
} elseif (mb_strlen($link['icon']) <= 4 && preg_match('/[\x{1F000}-\x{1F9FF}]/u', $link['icon'])) {
|
||||
echo '<span class="msd-emoji-icon">' . esc_html($link['icon']) . '</span>';
|
||||
if (!empty($link["icon"])) {
|
||||
if (strpos($link["icon"], "dashicons-") === 0) {
|
||||
echo '<span class="dashicons ' .
|
||||
esc_attr($link["icon"]) .
|
||||
'"></span>';
|
||||
} elseif (
|
||||
mb_strlen($link["icon"]) <= 4 &&
|
||||
preg_match("/[\x{1F000}-\x{1F9FF}]/u", $link["icon"])
|
||||
) {
|
||||
echo '<span class="msd-emoji-icon">' .
|
||||
esc_html($link["icon"]) .
|
||||
"</span>";
|
||||
}
|
||||
}
|
||||
|
||||
echo '<span>' . esc_html($link['title']) . '</span>';
|
||||
echo '</a>';
|
||||
echo "<span>" . esc_html($link["title"]) . "</span>";
|
||||
echo "</a>";
|
||||
}
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
echo '<div class="msd-widget-footer">';
|
||||
echo '<button class="button button-secondary button-small" onclick="MSD.showQuickLinksModal()">' . __('Edit Links', 'wp-multisite-dashboard') . '</button>';
|
||||
echo '</div>';
|
||||
echo '<button class="button button-secondary button-small" onclick="MSD.showQuickLinksModal()">' .
|
||||
__("Edit Links", "wp-multisite-dashboard") .
|
||||
"</button>";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
public function render_todo_widget() {
|
||||
public function render_todo_widget()
|
||||
{
|
||||
echo '<div id="msd-todo-widget" class="msd-widget-content" data-widget="todo_items">';
|
||||
echo '<button class="msd-refresh-btn" title="Refresh" data-widget="todo_items">↻</button>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' . __('Loading...', 'wp-multisite-dashboard') . '</div>';
|
||||
echo '</div>';
|
||||
echo '<div class="msd-loading"><span class="msd-spinner"></span>' .
|
||||
__("Loading...", "wp-multisite-dashboard") .
|
||||
"</div>";
|
||||
echo "</div>";
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,148 +1,278 @@
|
|||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
}
|
||||
|
||||
class WP_MSD_Settings_Manager {
|
||||
|
||||
public function render_settings_page() {
|
||||
if (isset($_POST['submit']) && wp_verify_nonce($_POST['msd_settings_nonce'], 'msd_settings')) {
|
||||
class WP_MSD_Settings_Manager
|
||||
{
|
||||
public function render_settings_page()
|
||||
{
|
||||
if (
|
||||
isset($_POST["submit"]) &&
|
||||
wp_verify_nonce($_POST["msd_settings_nonce"], "msd_settings")
|
||||
) {
|
||||
$this->save_settings();
|
||||
return;
|
||||
}
|
||||
|
||||
$widget_options = [
|
||||
'msd_network_overview' => 'Network Overview',
|
||||
'msd_quick_site_management' => 'Quick Site Management',
|
||||
'msd_storage_performance' => 'Storage Usage',
|
||||
'msd_server_info' => 'Server Information',
|
||||
'msd_quick_links' => 'Quick Links',
|
||||
'msd_version_info' => 'Version Information',
|
||||
'msd_custom_news' => 'Network News',
|
||||
'msd_user_management' => 'User Management',
|
||||
'msd_contact_info' => 'Contact Information',
|
||||
'msd_last_edits' => 'Recent Network Activity',
|
||||
'msd_todo_widget' => 'Todo List'
|
||||
"msd_network_overview" => __(
|
||||
"Network Overview",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_quick_site_management" => __(
|
||||
"Quick Site Management",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_storage_performance" => __(
|
||||
"Storage Usage",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_server_info" => __(
|
||||
"Server Information",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_quick_links" => __("Quick Links", "wp-multisite-dashboard"),
|
||||
"msd_version_info" => __(
|
||||
"Version Information",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_custom_news" => __("Network News", "wp-multisite-dashboard"),
|
||||
"msd_user_management" => __(
|
||||
"User Management",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_contact_info" => __(
|
||||
"Contact Information",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_last_edits" => __(
|
||||
"Recent Network Activity",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_todo_widget" => __("Todo List", "wp-multisite-dashboard"),
|
||||
];
|
||||
|
||||
include WP_MSD_PLUGIN_DIR . 'templates/settings-page.php';
|
||||
include WP_MSD_PLUGIN_DIR . "templates/settings-page.php";
|
||||
}
|
||||
|
||||
private function save_settings() {
|
||||
private function save_settings()
|
||||
{
|
||||
$enabled_widgets = [];
|
||||
$widget_options = [
|
||||
'msd_network_overview',
|
||||
'msd_quick_site_management',
|
||||
'msd_storage_performance',
|
||||
'msd_server_info',
|
||||
'msd_quick_links',
|
||||
'msd_version_info',
|
||||
'msd_custom_news',
|
||||
'msd_user_management',
|
||||
'msd_contact_info',
|
||||
'msd_last_edits',
|
||||
'msd_todo_widget'
|
||||
"msd_network_overview",
|
||||
"msd_quick_site_management",
|
||||
"msd_storage_performance",
|
||||
"msd_server_info",
|
||||
"msd_quick_links",
|
||||
"msd_version_info",
|
||||
"msd_custom_news",
|
||||
"msd_user_management",
|
||||
"msd_contact_info",
|
||||
"msd_last_edits",
|
||||
"msd_todo_widget",
|
||||
];
|
||||
|
||||
foreach ($widget_options as $widget_id) {
|
||||
if (isset($_POST['widgets'][$widget_id])) {
|
||||
if (isset($_POST["widgets"][$widget_id])) {
|
||||
$enabled_widgets[$widget_id] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
update_site_option('msd_enabled_widgets', $enabled_widgets);
|
||||
update_site_option("msd_enabled_widgets", $enabled_widgets);
|
||||
|
||||
$disabled_system_widgets = [];
|
||||
if (isset($_POST['system_widgets']) && is_array($_POST['system_widgets'])) {
|
||||
$available_widgets = $this->get_available_system_widgets();
|
||||
foreach ($available_widgets as $widget_id => $widget_data) {
|
||||
if (!$widget_data['is_custom'] && !isset($_POST['system_widgets'][$widget_id])) {
|
||||
$all_available_widgets = $this->get_all_possible_widgets();
|
||||
|
||||
if (
|
||||
isset($_POST["system_widgets"]) &&
|
||||
is_array($_POST["system_widgets"])
|
||||
) {
|
||||
foreach ($all_available_widgets as $widget_id => $widget_data) {
|
||||
if (
|
||||
!$widget_data["is_custom"] &&
|
||||
!isset($_POST["system_widgets"][$widget_id])
|
||||
) {
|
||||
$disabled_system_widgets[] = $widget_id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($all_available_widgets as $widget_id => $widget_data) {
|
||||
if (!$widget_data["is_custom"]) {
|
||||
$disabled_system_widgets[] = $widget_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_site_option('msd_disabled_system_widgets', $disabled_system_widgets);
|
||||
update_site_option(
|
||||
"msd_disabled_system_widgets",
|
||||
$disabled_system_widgets
|
||||
);
|
||||
|
||||
wp_safe_redirect(add_query_arg('updated', 'true', network_admin_url('settings.php?page=msd-settings')));
|
||||
exit;
|
||||
wp_safe_redirect(
|
||||
add_query_arg(
|
||||
"updated",
|
||||
"true",
|
||||
network_admin_url("settings.php?page=msd-settings")
|
||||
)
|
||||
);
|
||||
exit();
|
||||
}
|
||||
|
||||
public function get_available_system_widgets() {
|
||||
$known_system_widgets = [
|
||||
'network_dashboard_right_now' => [
|
||||
'id' => 'network_dashboard_right_now',
|
||||
'title' => 'Right Now',
|
||||
'context' => 'normal',
|
||||
'priority' => 'core',
|
||||
'is_custom' => false,
|
||||
'is_system' => true
|
||||
public function get_available_system_widgets()
|
||||
{
|
||||
$cached_widgets = get_site_transient("msd_detected_widgets");
|
||||
$known_system_widgets = $this->get_known_system_widgets();
|
||||
|
||||
if ($cached_widgets && is_array($cached_widgets)) {
|
||||
return array_merge($known_system_widgets, $cached_widgets);
|
||||
}
|
||||
|
||||
return $known_system_widgets;
|
||||
}
|
||||
|
||||
private function get_known_system_widgets()
|
||||
{
|
||||
return [
|
||||
"network_dashboard_right_now" => [
|
||||
"id" => "network_dashboard_right_now",
|
||||
"title" => __("Right Now", "wp-multisite-dashboard"),
|
||||
"context" => "normal",
|
||||
"priority" => "core",
|
||||
"is_custom" => false,
|
||||
"is_system" => true,
|
||||
],
|
||||
'dashboard_activity' => [
|
||||
'id' => 'dashboard_activity',
|
||||
'title' => 'Activity',
|
||||
'context' => 'normal',
|
||||
'priority' => 'high',
|
||||
'is_custom' => false,
|
||||
'is_system' => true
|
||||
"dashboard_activity" => [
|
||||
"id" => "dashboard_activity",
|
||||
"title" => __("Activity", "wp-multisite-dashboard"),
|
||||
"context" => "normal",
|
||||
"priority" => "high",
|
||||
"is_custom" => false,
|
||||
"is_system" => true,
|
||||
],
|
||||
'dashboard_plugins' => [
|
||||
'id' => 'dashboard_plugins',
|
||||
'title' => 'Plugins',
|
||||
'context' => 'normal',
|
||||
'priority' => 'core',
|
||||
'is_custom' => false,
|
||||
'is_system' => true
|
||||
"dashboard_plugins" => [
|
||||
"id" => "dashboard_plugins",
|
||||
"title" => __("Plugins", "wp-multisite-dashboard"),
|
||||
"context" => "normal",
|
||||
"priority" => "core",
|
||||
"is_custom" => false,
|
||||
"is_system" => true,
|
||||
],
|
||||
'dashboard_primary' => [
|
||||
'id' => 'dashboard_primary',
|
||||
'title' => 'WordPress Events and News',
|
||||
'context' => 'side',
|
||||
'priority' => 'core',
|
||||
'is_custom' => false,
|
||||
'is_system' => true
|
||||
"dashboard_primary" => [
|
||||
"id" => "dashboard_primary",
|
||||
"title" => __(
|
||||
"WordPress Events and News",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"context" => "side",
|
||||
"priority" => "core",
|
||||
"is_custom" => false,
|
||||
"is_system" => true,
|
||||
],
|
||||
"dashboard_secondary" => [
|
||||
"id" => "dashboard_secondary",
|
||||
"title" => __("Other WordPress News", "wp-multisite-dashboard"),
|
||||
"context" => "side",
|
||||
"priority" => "core",
|
||||
"is_custom" => false,
|
||||
"is_system" => true,
|
||||
],
|
||||
'dashboard_secondary' => [
|
||||
'id' => 'dashboard_secondary',
|
||||
'title' => 'Other WordPress News',
|
||||
'context' => 'side',
|
||||
'priority' => 'core',
|
||||
'is_custom' => false,
|
||||
'is_system' => true
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
$available_widgets = $known_system_widgets;
|
||||
private function get_all_possible_widgets()
|
||||
{
|
||||
$known_widgets = $this->get_known_system_widgets();
|
||||
$cached_widgets = get_site_transient("msd_detected_widgets");
|
||||
$stored_disabled = get_site_option("msd_disabled_system_widgets", []);
|
||||
|
||||
$all_widgets = $known_widgets;
|
||||
|
||||
$cached_widgets = get_site_transient('msd_detected_widgets');
|
||||
if ($cached_widgets && is_array($cached_widgets)) {
|
||||
foreach ($cached_widgets as $widget_id => $widget_data) {
|
||||
if (!isset($available_widgets[$widget_id])) {
|
||||
$available_widgets[$widget_id] = $widget_data;
|
||||
if (!isset($all_widgets[$widget_id])) {
|
||||
$all_widgets[$widget_id] = $widget_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $available_widgets;
|
||||
foreach ($stored_disabled as $widget_id) {
|
||||
if (!isset($all_widgets[$widget_id])) {
|
||||
$all_widgets[$widget_id] = [
|
||||
"id" => $widget_id,
|
||||
"title" => $this->generate_widget_title_from_id($widget_id),
|
||||
"context" => "unknown",
|
||||
"priority" => "default",
|
||||
"is_custom" => false,
|
||||
"is_system" => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $all_widgets;
|
||||
}
|
||||
|
||||
public function get_widget_description($widget_id) {
|
||||
private function generate_widget_title_from_id($widget_id)
|
||||
{
|
||||
$title = str_replace(["_", "-"], " ", $widget_id);
|
||||
$title = ucwords($title);
|
||||
return $title;
|
||||
}
|
||||
|
||||
public function get_widget_description($widget_id)
|
||||
{
|
||||
$descriptions = [
|
||||
'msd_network_overview' => __('Network statistics and multisite configuration information', 'wp-multisite-dashboard'),
|
||||
'msd_quick_site_management' => __('Quick access to recently active sites with favicons', 'wp-multisite-dashboard'),
|
||||
'msd_storage_performance' => __('Top 5 sites by storage usage and performance insights', 'wp-multisite-dashboard'),
|
||||
'msd_server_info' => __('Server specifications and WordPress environment details', 'wp-multisite-dashboard'),
|
||||
'msd_quick_links' => __('Customizable quick access links for common tasks with drag-and-drop reordering', 'wp-multisite-dashboard'),
|
||||
'msd_version_info' => __('Plugin version and system information with help links', 'wp-multisite-dashboard'),
|
||||
'msd_custom_news' => __('Custom news sources and updates', 'wp-multisite-dashboard'),
|
||||
'msd_network_settings' => __('Network configuration and settings overview', 'wp-multisite-dashboard'),
|
||||
'msd_user_management' => __('Recent user registrations and user management tools', 'wp-multisite-dashboard'),
|
||||
'msd_contact_info' => __('Network administrator contact information with instant messaging and QR code support', 'wp-multisite-dashboard'),
|
||||
'msd_last_edits' => __('Recent posts, pages, and content activity across the network', 'wp-multisite-dashboard'),
|
||||
'msd_todo_widget' => __('Simple todo list for network administrators with priority levels', 'wp-multisite-dashboard')
|
||||
"msd_network_overview" => __(
|
||||
"Network statistics and multisite configuration information",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_quick_site_management" => __(
|
||||
"Quick access to recently active sites with favicons",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_storage_performance" => __(
|
||||
"Top 5 sites by storage usage and performance insights",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_server_info" => __(
|
||||
"Server specifications and WordPress environment details",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_quick_links" => __(
|
||||
"Customizable quick access links for common tasks with drag-and-drop reordering",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_version_info" => __(
|
||||
"Plugin version and system information with help links",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_custom_news" => __(
|
||||
"Custom news sources and updates",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_network_settings" => __(
|
||||
"Network configuration and settings overview",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_user_management" => __(
|
||||
"Recent user registrations and user management tools",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_contact_info" => __(
|
||||
"Network administrator contact information with instant messaging and QR code support",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_last_edits" => __(
|
||||
"Recent posts, pages, and content activity across the network",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_todo_widget" => __(
|
||||
"Simple todo list for network administrators with priority levels",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
];
|
||||
|
||||
return $descriptions[$widget_id] ?? '';
|
||||
return $descriptions[$widget_id] ?? "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,518 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WP_MSD_Todo_Manager {
|
||||
|
||||
private $wpdb;
|
||||
private $table_name;
|
||||
private $cache_group = 'msd_todos';
|
||||
|
||||
public function __construct() {
|
||||
global $wpdb;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->table_name = $wpdb->base_prefix . 'msd_todo_list';
|
||||
}
|
||||
|
||||
public function create_todo_table() {
|
||||
$charset_collate = $this->wpdb->get_charset_collate();
|
||||
|
||||
$sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
|
||||
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
item varchar(500) NOT NULL,
|
||||
completed tinyint(1) DEFAULT 0,
|
||||
priority enum('low','medium','high') DEFAULT 'medium',
|
||||
user_id bigint(20) unsigned NOT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
updated_at datetime DEFAULT NULL,
|
||||
due_date datetime DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY user_id (user_id),
|
||||
KEY completed (completed),
|
||||
KEY priority (priority),
|
||||
KEY created_at (created_at)
|
||||
) $charset_collate;";
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
||||
dbDelta($sql);
|
||||
}
|
||||
|
||||
public function get_todo_items($limit = 50, $user_id = null, $completed = null) {
|
||||
$cache_key = "todo_items_{$limit}_" . ($user_id ?? 'all') . "_" . ($completed ?? 'all');
|
||||
$cached = wp_cache_get($cache_key, $this->cache_group);
|
||||
|
||||
if ($cached !== false) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$where_clauses = ['1=1'];
|
||||
$where_values = [];
|
||||
|
||||
if ($user_id !== null) {
|
||||
$where_clauses[] = 'user_id = %d';
|
||||
$where_values[] = $user_id;
|
||||
}
|
||||
|
||||
if ($completed !== null) {
|
||||
$where_clauses[] = 'completed = %d';
|
||||
$where_values[] = $completed ? 1 : 0;
|
||||
}
|
||||
|
||||
$where_sql = implode(' AND ', $where_clauses);
|
||||
|
||||
$sql = "SELECT * FROM {$this->table_name}
|
||||
WHERE {$where_sql}
|
||||
ORDER BY completed ASC, priority DESC, created_at DESC
|
||||
LIMIT %d";
|
||||
|
||||
$where_values[] = $limit;
|
||||
|
||||
$prepared_sql = $this->wpdb->prepare($sql, ...$where_values);
|
||||
$results = $this->wpdb->get_results($prepared_sql, ARRAY_A);
|
||||
|
||||
$todos = [];
|
||||
foreach ($results as $row) {
|
||||
$user_data = get_userdata($row['user_id']);
|
||||
$todos[] = [
|
||||
'id' => intval($row['id']),
|
||||
'item' => $row['item'],
|
||||
'completed' => (bool)$row['completed'],
|
||||
'priority' => $row['priority'],
|
||||
'user_id' => intval($row['user_id']),
|
||||
'user_name' => $user_data ? $user_data->display_name : 'Unknown User',
|
||||
'user_avatar' => $user_data ? get_avatar_url($user_data->ID, 32) : '',
|
||||
'created_at' => $row['created_at'],
|
||||
'updated_at' => $row['updated_at'],
|
||||
'due_date' => $row['due_date'],
|
||||
'created_human' => human_time_diff(strtotime($row['created_at'])) . ' ago',
|
||||
'due_human' => $row['due_date'] ? human_time_diff(strtotime($row['due_date'])) : null,
|
||||
'is_overdue' => $row['due_date'] && strtotime($row['due_date']) < current_time('timestamp') && !$row['completed'],
|
||||
'priority_label' => $this->get_priority_label($row['priority']),
|
||||
'priority_class' => $this->get_priority_class($row['priority'])
|
||||
];
|
||||
}
|
||||
|
||||
wp_cache_set($cache_key, $todos, $this->cache_group, 1800);
|
||||
return $todos;
|
||||
}
|
||||
|
||||
public function add_todo_item($item, $priority = 'medium', $user_id = null, $due_date = null) {
|
||||
if (empty($item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user_id = $user_id ?: get_current_user_id();
|
||||
|
||||
if (!$user_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'item' => sanitize_text_field($item),
|
||||
'priority' => in_array($priority, ['low', 'medium', 'high']) ? $priority : 'medium',
|
||||
'user_id' => $user_id,
|
||||
'created_at' => current_time('mysql'),
|
||||
'due_date' => $due_date ? date('Y-m-d H:i:s', strtotime($due_date)) : null
|
||||
];
|
||||
|
||||
$result = $this->wpdb->insert(
|
||||
$this->table_name,
|
||||
$data,
|
||||
['%s', '%s', '%d', '%s', '%s']
|
||||
);
|
||||
|
||||
if ($result !== false) {
|
||||
$this->clear_cache();
|
||||
|
||||
if (class_exists('WP_MSD_Network_Data')) {
|
||||
$network_data = new WP_MSD_Network_Data();
|
||||
$network_data->log_activity(
|
||||
0,
|
||||
'todo_added',
|
||||
sprintf('Todo item added: %s', substr($item, 0, 50)),
|
||||
'low',
|
||||
$user_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function delete_todo_item($item_id, $user_id = null) {
|
||||
$item_id = intval($item_id);
|
||||
|
||||
if (!$item_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$where = ['id' => $item_id];
|
||||
$where_format = ['%d'];
|
||||
|
||||
if ($user_id) {
|
||||
$where['user_id'] = $user_id;
|
||||
$where_format[] = '%d';
|
||||
} elseif (!current_user_can('manage_network')) {
|
||||
$where['user_id'] = get_current_user_id();
|
||||
$where_format[] = '%d';
|
||||
}
|
||||
|
||||
$item = $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT item FROM {$this->table_name} WHERE id = %d",
|
||||
$item_id
|
||||
)
|
||||
);
|
||||
|
||||
$result = $this->wpdb->delete($this->table_name, $where, $where_format);
|
||||
|
||||
if ($result !== false && $item) {
|
||||
$this->clear_cache();
|
||||
|
||||
if (class_exists('WP_MSD_Network_Data')) {
|
||||
$network_data = new WP_MSD_Network_Data();
|
||||
$network_data->log_activity(
|
||||
0,
|
||||
'todo_deleted',
|
||||
sprintf('Todo item deleted: %s', substr($item->item, 0, 50)),
|
||||
'low'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function toggle_todo_item($item_id, $completed = null, $user_id = null) {
|
||||
$item_id = intval($item_id);
|
||||
|
||||
if (!$item_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$where_clause = 'id = %d';
|
||||
$where_values = [$item_id];
|
||||
|
||||
if ($user_id) {
|
||||
$where_clause .= ' AND user_id = %d';
|
||||
$where_values[] = $user_id;
|
||||
} elseif (!current_user_can('manage_network')) {
|
||||
$where_clause .= ' AND user_id = %d';
|
||||
$where_values[] = get_current_user_id();
|
||||
}
|
||||
|
||||
if ($completed === null) {
|
||||
$current_item = $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT completed FROM {$this->table_name} WHERE {$where_clause}",
|
||||
...$where_values
|
||||
)
|
||||
);
|
||||
|
||||
if (!$current_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$completed = !$current_item->completed;
|
||||
}
|
||||
|
||||
$result = $this->wpdb->update(
|
||||
$this->table_name,
|
||||
[
|
||||
'completed' => $completed ? 1 : 0,
|
||||
'updated_at' => current_time('mysql')
|
||||
],
|
||||
['id' => $item_id],
|
||||
['%d', '%s'],
|
||||
['%d']
|
||||
);
|
||||
|
||||
if ($result !== false) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function update_todo_item($item_id, $data, $user_id = null) {
|
||||
$item_id = intval($item_id);
|
||||
|
||||
if (!$item_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowed_fields = ['item', 'priority', 'due_date', 'completed'];
|
||||
$update_data = [];
|
||||
$update_format = [];
|
||||
|
||||
foreach ($data as $field => $value) {
|
||||
if (!in_array($field, $allowed_fields)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($field) {
|
||||
case 'item':
|
||||
$update_data['item'] = sanitize_text_field($value);
|
||||
$update_format[] = '%s';
|
||||
break;
|
||||
case 'priority':
|
||||
if (in_array($value, ['low', 'medium', 'high'])) {
|
||||
$update_data['priority'] = $value;
|
||||
$update_format[] = '%s';
|
||||
}
|
||||
break;
|
||||
case 'due_date':
|
||||
$update_data['due_date'] = $value ? date('Y-m-d H:i:s', strtotime($value)) : null;
|
||||
$update_format[] = '%s';
|
||||
break;
|
||||
case 'completed':
|
||||
$update_data['completed'] = $value ? 1 : 0;
|
||||
$update_format[] = '%d';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($update_data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$update_data['updated_at'] = current_time('mysql');
|
||||
$update_format[] = '%s';
|
||||
|
||||
$where = ['id' => $item_id];
|
||||
$where_format = ['%d'];
|
||||
|
||||
if ($user_id) {
|
||||
$where['user_id'] = $user_id;
|
||||
$where_format[] = '%d';
|
||||
} elseif (!current_user_can('manage_network')) {
|
||||
$where['user_id'] = get_current_user_id();
|
||||
$where_format[] = '%d';
|
||||
}
|
||||
|
||||
$result = $this->wpdb->update(
|
||||
$this->table_name,
|
||||
$update_data,
|
||||
$where,
|
||||
$update_format,
|
||||
$where_format
|
||||
);
|
||||
|
||||
if ($result !== false) {
|
||||
$this->clear_cache();
|
||||
}
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
public function get_todo_statistics() {
|
||||
$cache_key = 'todo_statistics';
|
||||
$cached = wp_cache_get($cache_key, $this->cache_group);
|
||||
|
||||
if ($cached !== false) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$stats = [
|
||||
'total' => 0,
|
||||
'completed' => 0,
|
||||
'pending' => 0,
|
||||
'overdue' => 0,
|
||||
'by_priority' => [
|
||||
'high' => 0,
|
||||
'medium' => 0,
|
||||
'low' => 0
|
||||
],
|
||||
'by_user' => []
|
||||
];
|
||||
|
||||
$total_result = $this->wpdb->get_row(
|
||||
"SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(completed) as completed,
|
||||
SUM(CASE WHEN completed = 0 THEN 1 ELSE 0 END) as pending,
|
||||
SUM(CASE WHEN due_date < NOW() AND completed = 0 THEN 1 ELSE 0 END) as overdue
|
||||
FROM {$this->table_name}"
|
||||
);
|
||||
|
||||
if ($total_result) {
|
||||
$stats['total'] = intval($total_result->total);
|
||||
$stats['completed'] = intval($total_result->completed);
|
||||
$stats['pending'] = intval($total_result->pending);
|
||||
$stats['overdue'] = intval($total_result->overdue);
|
||||
}
|
||||
|
||||
$priority_results = $this->wpdb->get_results(
|
||||
"SELECT priority, COUNT(*) as count
|
||||
FROM {$this->table_name}
|
||||
WHERE completed = 0
|
||||
GROUP BY priority"
|
||||
);
|
||||
|
||||
foreach ($priority_results as $priority_result) {
|
||||
if (isset($stats['by_priority'][$priority_result->priority])) {
|
||||
$stats['by_priority'][$priority_result->priority] = intval($priority_result->count);
|
||||
}
|
||||
}
|
||||
|
||||
$user_results = $this->wpdb->get_results(
|
||||
"SELECT user_id, COUNT(*) as total, SUM(completed) as completed
|
||||
FROM {$this->table_name}
|
||||
GROUP BY user_id
|
||||
ORDER BY total DESC
|
||||
LIMIT 10"
|
||||
);
|
||||
|
||||
foreach ($user_results as $user_result) {
|
||||
$user_data = get_userdata($user_result->user_id);
|
||||
$stats['by_user'][] = [
|
||||
'user_id' => intval($user_result->user_id),
|
||||
'user_name' => $user_data ? $user_data->display_name : 'Unknown User',
|
||||
'total' => intval($user_result->total),
|
||||
'completed' => intval($user_result->completed),
|
||||
'pending' => intval($user_result->total) - intval($user_result->completed)
|
||||
];
|
||||
}
|
||||
|
||||
wp_cache_set($cache_key, $stats, $this->cache_group, 3600);
|
||||
return $stats;
|
||||
}
|
||||
|
||||
public function get_user_todos($user_id, $limit = 20) {
|
||||
return $this->get_todo_items($limit, $user_id);
|
||||
}
|
||||
|
||||
public function get_overdue_todos($limit = 20) {
|
||||
$cache_key = "overdue_todos_{$limit}";
|
||||
$cached = wp_cache_get($cache_key, $this->cache_group);
|
||||
|
||||
if ($cached !== false) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$sql = "SELECT * FROM {$this->table_name}
|
||||
WHERE due_date < NOW()
|
||||
AND completed = 0
|
||||
ORDER BY due_date ASC
|
||||
LIMIT %d";
|
||||
|
||||
$results = $this->wpdb->get_results(
|
||||
$this->wpdb->prepare($sql, $limit),
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
$todos = [];
|
||||
foreach ($results as $row) {
|
||||
$user_data = get_userdata($row['user_id']);
|
||||
$todos[] = [
|
||||
'id' => intval($row['id']),
|
||||
'item' => $row['item'],
|
||||
'priority' => $row['priority'],
|
||||
'user_id' => intval($row['user_id']),
|
||||
'user_name' => $user_data ? $user_data->display_name : 'Unknown User',
|
||||
'due_date' => $row['due_date'],
|
||||
'due_human' => human_time_diff(strtotime($row['due_date'])) . ' overdue',
|
||||
'created_at' => $row['created_at'],
|
||||
'priority_label' => $this->get_priority_label($row['priority']),
|
||||
'priority_class' => $this->get_priority_class($row['priority'])
|
||||
];
|
||||
}
|
||||
|
||||
wp_cache_set($cache_key, $todos, $this->cache_group, 1800);
|
||||
return $todos;
|
||||
}
|
||||
|
||||
public function bulk_delete_completed($user_id = null) {
|
||||
$where_clause = 'completed = 1';
|
||||
$where_values = [];
|
||||
|
||||
if ($user_id) {
|
||||
$where_clause .= ' AND user_id = %d';
|
||||
$where_values[] = $user_id;
|
||||
} elseif (!current_user_can('manage_network')) {
|
||||
$where_clause .= ' AND user_id = %d';
|
||||
$where_values[] = get_current_user_id();
|
||||
}
|
||||
|
||||
if (!empty($where_values)) {
|
||||
$sql = "DELETE FROM {$this->table_name} WHERE {$where_clause}";
|
||||
$result = $this->wpdb->query($this->wpdb->prepare($sql, ...$where_values));
|
||||
} else {
|
||||
$result = $this->wpdb->delete($this->table_name, ['completed' => 1], ['%d']);
|
||||
}
|
||||
|
||||
if ($result !== false) {
|
||||
$this->clear_cache();
|
||||
|
||||
if (class_exists('WP_MSD_Network_Data')) {
|
||||
$network_data = new WP_MSD_Network_Data();
|
||||
$network_data->log_activity(
|
||||
0,
|
||||
'todo_bulk_delete',
|
||||
sprintf('Bulk deleted %d completed todo items', $result),
|
||||
'medium'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
private function get_priority_label($priority) {
|
||||
$labels = [
|
||||
'low' => __('Low', 'wp-multisite-dashboard'),
|
||||
'medium' => __('Medium', 'wp-multisite-dashboard'),
|
||||
'high' => __('High', 'wp-multisite-dashboard')
|
||||
];
|
||||
return $labels[$priority] ?? $labels['medium'];
|
||||
}
|
||||
|
||||
private function get_priority_class($priority) {
|
||||
$classes = [
|
||||
'low' => 'msd-priority-low',
|
||||
'medium' => 'msd-priority-medium',
|
||||
'high' => 'msd-priority-high'
|
||||
];
|
||||
return $classes[$priority] ?? $classes['medium'];
|
||||
}
|
||||
|
||||
public function clear_cache() {
|
||||
wp_cache_flush_group($this->cache_group);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function cleanup_old_todos($days = 90) {
|
||||
if (!current_user_can('manage_network')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cutoff_date = date('Y-m-d H:i:s', strtotime("-{$days} days"));
|
||||
|
||||
$result = $this->wpdb->delete(
|
||||
$this->table_name,
|
||||
[
|
||||
'completed' => 1,
|
||||
'updated_at' => $cutoff_date
|
||||
],
|
||||
['%d', '%s']
|
||||
);
|
||||
|
||||
if ($result !== false) {
|
||||
$this->clear_cache();
|
||||
|
||||
if (class_exists('WP_MSD_Network_Data')) {
|
||||
$network_data = new WP_MSD_Network_Data();
|
||||
$network_data->log_activity(
|
||||
0,
|
||||
'todo_cleanup',
|
||||
sprintf('Cleaned up %d old completed todo items', $result),
|
||||
'medium'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result !== false;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1,36 +1,42 @@
|
|||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$contact_info = get_site_option('msd_contact_info', [
|
||||
'name' => get_network_option(null, 'site_name'),
|
||||
'email' => get_network_option(null, 'admin_email'),
|
||||
'phone' => '',
|
||||
'website' => network_home_url(),
|
||||
'description' => 'Network Administrator Contact Information',
|
||||
'qq' => '',
|
||||
'wechat' => '',
|
||||
'whatsapp' => '',
|
||||
'telegram' => '',
|
||||
'qr_code' => ''
|
||||
$contact_info = get_site_option("msd_contact_info", [
|
||||
"name" => get_network_option(null, "site_name"),
|
||||
"email" => get_network_option(null, "admin_email"),
|
||||
"phone" => "",
|
||||
"website" => network_home_url(),
|
||||
"description" => __(
|
||||
"Network Administrator Contact Information",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"qq" => "",
|
||||
"wechat" => "",
|
||||
"whatsapp" => "",
|
||||
"telegram" => "",
|
||||
"qr_code" => "",
|
||||
]);
|
||||
|
||||
$news_sources = get_site_option('msd_news_sources', [
|
||||
$news_sources = get_site_option("msd_news_sources", [
|
||||
[
|
||||
'name' => 'WordPress News',
|
||||
'url' => 'https://wordpress.org/news/feed/',
|
||||
'enabled' => true
|
||||
]
|
||||
"name" => __("WordPress News", "wp-multisite-dashboard"),
|
||||
"url" => "https://wordpress.org/news/feed/",
|
||||
"enabled" => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$quick_links = get_site_option('msd_quick_links', []);
|
||||
$quick_links = get_site_option("msd_quick_links", []);
|
||||
?>
|
||||
|
||||
<div id="msd-contact-info-modal" class="msd-modal" style="display: none;">
|
||||
<div class="msd-modal-content">
|
||||
<div class="msd-modal-header">
|
||||
<h3><?php _e('Edit Contact Information', 'wp-multisite-dashboard'); ?></h3>
|
||||
<h3><?php _e(
|
||||
"Edit Contact Information",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h3>
|
||||
<button type="button" class="msd-modal-close" onclick="MSD.hideContactInfoModal()">×</button>
|
||||
</div>
|
||||
|
||||
|
@ -38,28 +44,59 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-contact-form">
|
||||
<div class="msd-form-section">
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Organization Name:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="text" id="msd-contact-name" value="<?php echo esc_attr($contact_info['name']); ?>" placeholder="<?php esc_attr_e('Network Administrator', 'wp-multisite-dashboard'); ?>">
|
||||
<label><?php _e(
|
||||
"Organization Name:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></label>
|
||||
<input type="text" id="msd-contact-name" value="<?php echo esc_attr(
|
||||
$contact_info["name"]
|
||||
); ?>" placeholder="<?php esc_attr_e(
|
||||
"Network Administrator",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Email:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="email" id="msd-contact-email" value="<?php echo esc_attr($contact_info['email']); ?>" placeholder="admin@example.com">
|
||||
<label><?php _e(
|
||||
"Email:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></label>
|
||||
<input type="email" id="msd-contact-email" value="<?php echo esc_attr(
|
||||
$contact_info["email"]
|
||||
); ?>" placeholder="admin@example.com">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Phone:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="text" id="msd-contact-phone" value="<?php echo esc_attr($contact_info['phone']); ?>" placeholder="+1 234 567 8900">
|
||||
<label><?php _e(
|
||||
"Phone:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></label>
|
||||
<input type="text" id="msd-contact-phone" value="<?php echo esc_attr(
|
||||
$contact_info["phone"]
|
||||
); ?>" placeholder="+1 234 567 8900">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Website:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="url" id="msd-contact-website" value="<?php echo esc_attr($contact_info['website']); ?>" placeholder="https://example.com">
|
||||
<label><?php _e(
|
||||
"Website:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></label>
|
||||
<input type="url" id="msd-contact-website" value="<?php echo esc_attr(
|
||||
$contact_info["website"]
|
||||
); ?>" placeholder="https://example.com">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Description:', 'wp-multisite-dashboard'); ?></label>
|
||||
<textarea id="msd-contact-description" placeholder="<?php esc_attr_e('Brief description or role', 'wp-multisite-dashboard'); ?>"><?php echo esc_textarea($contact_info['description']); ?></textarea>
|
||||
<label><?php _e(
|
||||
"Description:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></label>
|
||||
<textarea id="msd-contact-description" placeholder="<?php esc_attr_e(
|
||||
"Brief description or role",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>"><?php echo esc_textarea(
|
||||
$contact_info["description"]
|
||||
); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -68,17 +105,27 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-admin-users"></span>
|
||||
<?php _e('QQ:', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("QQ:", "wp-multisite-dashboard"); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-qq" value="<?php echo esc_attr($contact_info['qq']); ?>" placeholder="1234567890">
|
||||
<input type="text" id="msd-contact-qq" value="<?php echo esc_attr(
|
||||
$contact_info["qq"]
|
||||
); ?>" placeholder="1234567890">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-format-chat"></span>
|
||||
<?php _e('WeChat:', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"WeChat:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-wechat" value="<?php echo esc_attr($contact_info['wechat']); ?>" placeholder="WeChat_ID">
|
||||
<input type="text" id="msd-contact-wechat" value="<?php echo esc_attr(
|
||||
$contact_info["wechat"]
|
||||
); ?>" placeholder="<?php esc_attr_e(
|
||||
"WeChat ID",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -86,32 +133,62 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-smartphone"></span>
|
||||
<?php _e('WhatsApp:', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"WhatsApp:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-whatsapp" value="<?php echo esc_attr($contact_info['whatsapp']); ?>" placeholder="+1234567890">
|
||||
<input type="text" id="msd-contact-whatsapp" value="<?php echo esc_attr(
|
||||
$contact_info["whatsapp"]
|
||||
); ?>" placeholder="+1234567890">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-email-alt"></span>
|
||||
<?php _e('Telegram:', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"Telegram:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-telegram" value="<?php echo esc_attr($contact_info['telegram']); ?>" placeholder="@username">
|
||||
<input type="text" id="msd-contact-telegram" value="<?php echo esc_attr(
|
||||
$contact_info["telegram"]
|
||||
); ?>" placeholder="@username">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-form-section">
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('QR Code Image URL:', 'wp-multisite-dashboard'); ?></label>
|
||||
<label><?php _e(
|
||||
"QR Code Image URL:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></label>
|
||||
<div class="msd-qr-input-group">
|
||||
<input type="url" id="msd-contact-qr-code" value="<?php echo esc_attr($contact_info['qr_code']); ?>" placeholder="https://example.com/qr-code.png">
|
||||
<button type="button" class="button" onclick="MSD.selectQRImage()"><?php _e('Select Image', 'wp-multisite-dashboard'); ?></button>
|
||||
<input type="url" id="msd-contact-qr-code" value="<?php echo esc_attr(
|
||||
$contact_info["qr_code"]
|
||||
); ?>" placeholder="https://example.com/qr-code.png">
|
||||
<button type="button" class="button" onclick="MSD.selectQRImage()"><?php _e(
|
||||
"Select Image",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></button>
|
||||
</div>
|
||||
<p class="description"><?php _e('Upload or provide URL for a QR code image (WeChat, contact info, etc.)', 'wp-multisite-dashboard'); ?></p>
|
||||
<p class="description"><?php _e(
|
||||
"Upload or provide URL for a QR code image (WeChat, contact info, etc.)",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
|
||||
<div id="msd-qr-preview" class="msd-qr-preview" style="<?php echo empty($contact_info['qr_code']) ? 'display: none;' : ''; ?>">
|
||||
<img src="<?php echo esc_url($contact_info['qr_code']); ?>" alt="QR Code Preview" class="msd-qr-preview-img">
|
||||
<div id="msd-qr-preview" class="msd-qr-preview" style="<?php echo empty(
|
||||
$contact_info["qr_code"]
|
||||
)
|
||||
? "display: none;"
|
||||
: ""; ?>">
|
||||
<img src="<?php echo esc_url(
|
||||
$contact_info["qr_code"]
|
||||
); ?>" alt="<?php esc_attr_e(
|
||||
"QR Code Preview",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>" class="msd-qr-preview-img">
|
||||
<button type="button" class="msd-qr-remove" onclick="MSD.removeQRCode()">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -121,10 +198,10 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
|
||||
<div class="msd-modal-footer">
|
||||
<button type="button" class="button button-primary" onclick="MSD.saveContactInfo()">
|
||||
<?php _e('Save Contact Info', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Save Contact Info", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.hideContactInfoModal()">
|
||||
<?php _e('Cancel', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Cancel", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -133,7 +210,10 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div id="msd-news-sources-modal" class="msd-modal" style="display: none;">
|
||||
<div class="msd-modal-content">
|
||||
<div class="msd-modal-header">
|
||||
<h3><?php _e('Configure News Sources', 'wp-multisite-dashboard'); ?></h3>
|
||||
<h3><?php _e(
|
||||
"Configure News Sources",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h3>
|
||||
<button type="button" class="msd-modal-close" onclick="MSD.hideNewsSourcesModal()">×</button>
|
||||
</div>
|
||||
|
||||
|
@ -144,13 +224,23 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-news-source-item">
|
||||
<div class="msd-source-row">
|
||||
<input type="text"
|
||||
placeholder="<?php esc_attr_e('Source Name', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_attr($source['name']); ?>"
|
||||
placeholder="<?php esc_attr_e(
|
||||
"Source Name",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>"
|
||||
value="<?php echo esc_attr(
|
||||
$source["name"]
|
||||
); ?>"
|
||||
class="msd-news-name"
|
||||
required>
|
||||
<input type="url"
|
||||
placeholder="<?php esc_attr_e('RSS Feed URL', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_url($source['url']); ?>"
|
||||
placeholder="<?php esc_attr_e(
|
||||
"RSS Feed URL",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>"
|
||||
value="<?php echo esc_url(
|
||||
$source["url"]
|
||||
); ?>"
|
||||
class="msd-news-url"
|
||||
required>
|
||||
</div>
|
||||
|
@ -159,12 +249,20 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<label class="msd-checkbox-label">
|
||||
<input type="checkbox"
|
||||
class="msd-news-enabled"
|
||||
<?php checked(!empty($source['enabled'])); ?>>
|
||||
<?php _e('Enabled', 'wp-multisite-dashboard'); ?>
|
||||
<?php checked(
|
||||
!empty($source["enabled"])
|
||||
); ?>>
|
||||
<?php _e(
|
||||
"Enabled",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</label>
|
||||
|
||||
<button type="button" class="msd-remove-source">
|
||||
<?php _e('Remove', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"Remove",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -175,22 +273,37 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-add-source-section">
|
||||
<button type="button" id="msd-add-news-source" class="button button-secondary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Add News Source', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Add News Source", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="msd-news-help">
|
||||
<h4><?php _e('Popular RSS Feeds', 'wp-multisite-dashboard'); ?></h4>
|
||||
<h4><?php _e(
|
||||
"Popular RSS Feeds",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h4>
|
||||
<div class="msd-rss-suggestions">
|
||||
<div class="msd-rss-suggestion">
|
||||
<strong>WenPai.org News</strong>
|
||||
<strong><?php _e(
|
||||
"WenPai.org News",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></strong>
|
||||
<code>https://wenpai.org/news/feed/</code>
|
||||
<span class="msd-rss-desc">Official WenPai.org news and updates</span>
|
||||
<span class="msd-rss-desc"><?php _e(
|
||||
"Official WenPai.org news and updates",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
</div>
|
||||
<div class="msd-rss-suggestion">
|
||||
<strong>WP TEA</strong>
|
||||
<strong><?php _e(
|
||||
"WP TEA",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></strong>
|
||||
<code>https://wptea.com/feed</code>
|
||||
<span class="msd-rss-desc">WordPress China community news and insights</span>
|
||||
<span class="msd-rss-desc"><?php _e(
|
||||
"WordPress China community news and insights",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -198,10 +311,10 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
|
||||
<div class="msd-modal-footer">
|
||||
<button type="button" class="button button-primary" onclick="MSD.saveNewsSources()">
|
||||
<?php _e('Save News Sources', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Save News Sources", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.hideNewsSourcesModal()">
|
||||
<?php _e('Cancel', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Cancel", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -210,7 +323,10 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div id="msd-quick-links-modal" class="msd-modal" style="display: none;">
|
||||
<div class="msd-modal-content">
|
||||
<div class="msd-modal-header">
|
||||
<h3><?php _e('Configure Quick Links', 'wp-multisite-dashboard'); ?></h3>
|
||||
<h3><?php _e(
|
||||
"Configure Quick Links",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h3>
|
||||
<button type="button" class="msd-modal-close" onclick="MSD.hideQuickLinksModal()">×</button>
|
||||
</div>
|
||||
|
||||
|
@ -221,33 +337,56 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-link-item">
|
||||
<div class="msd-link-row">
|
||||
<input type="text"
|
||||
placeholder="<?php esc_attr_e('Link Title', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_attr($link['title']); ?>"
|
||||
placeholder="<?php esc_attr_e(
|
||||
"Link Title",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>"
|
||||
value="<?php echo esc_attr(
|
||||
$link["title"]
|
||||
); ?>"
|
||||
class="msd-link-title"
|
||||
required>
|
||||
<input type="url"
|
||||
placeholder="https://example.com"
|
||||
value="<?php echo esc_url($link['url']); ?>"
|
||||
value="<?php echo esc_url(
|
||||
$link["url"]
|
||||
); ?>"
|
||||
class="msd-link-url"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="msd-link-options">
|
||||
<input type="text"
|
||||
placeholder="<?php esc_attr_e('dashicons-admin-home or 🏠', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_attr($link['icon']); ?>"
|
||||
placeholder="<?php esc_attr_e(
|
||||
"dashicons-admin-home or 🏠",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>"
|
||||
value="<?php echo esc_attr(
|
||||
$link["icon"]
|
||||
); ?>"
|
||||
class="msd-link-icon"
|
||||
title="<?php esc_attr_e('Icon (Dashicon class or emoji)', 'wp-multisite-dashboard'); ?>">
|
||||
title="<?php esc_attr_e(
|
||||
"Icon (Dashicon class or emoji)",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>">
|
||||
|
||||
<label class="msd-checkbox-label">
|
||||
<input type="checkbox"
|
||||
class="msd-link-newtab"
|
||||
<?php checked(!empty($link['new_tab'])); ?>>
|
||||
<?php _e('Open in new tab', 'wp-multisite-dashboard'); ?>
|
||||
<?php checked(
|
||||
!empty($link["new_tab"])
|
||||
); ?>>
|
||||
<?php _e(
|
||||
"Open in new tab",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</label>
|
||||
|
||||
<button type="button" class="msd-remove-link">
|
||||
<?php _e('Remove', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"Remove",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -258,64 +397,100 @@ $quick_links = get_site_option('msd_quick_links', []);
|
|||
<div class="msd-add-link-section">
|
||||
<button type="button" id="msd-add-link" class="button button-secondary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Add Link', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Add Link", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="msd-quick-links-help">
|
||||
<h4><?php _e('Icon Options', 'wp-multisite-dashboard'); ?></h4>
|
||||
<h4><?php _e("Icon Options", "wp-multisite-dashboard"); ?></h4>
|
||||
|
||||
<div class="msd-icon-types">
|
||||
<div class="msd-icon-type-section">
|
||||
<h5><?php _e('WordPress Dashicons', 'wp-multisite-dashboard'); ?></h5>
|
||||
<h5><?php _e(
|
||||
"WordPress Dashicons",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h5>
|
||||
<div class="msd-icon-examples">
|
||||
<div class="msd-icon-example">
|
||||
<span class="dashicons dashicons-admin-home"></span>
|
||||
<code>dashicons-admin-home</code>
|
||||
<span><?php _e('Home', 'wp-multisite-dashboard'); ?></span>
|
||||
<span><?php _e(
|
||||
"Home",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
</div>
|
||||
<div class="msd-icon-example">
|
||||
<span class="dashicons dashicons-chart-bar"></span>
|
||||
<code>dashicons-chart-bar</code>
|
||||
<span><?php _e('Analytics', 'wp-multisite-dashboard'); ?></span>
|
||||
<span><?php _e(
|
||||
"Analytics",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-icon-type-section">
|
||||
<h5><?php _e('Emojis', 'wp-multisite-dashboard'); ?></h5>
|
||||
<h5><?php _e(
|
||||
"Emojis",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h5>
|
||||
<div class="msd-icon-examples">
|
||||
<div class="msd-icon-example">
|
||||
<span class="msd-emoji">🏠</span>
|
||||
<code>🏠</code>
|
||||
<span><?php _e('Home', 'wp-multisite-dashboard'); ?></span>
|
||||
<span><?php _e(
|
||||
"Home",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
</div>
|
||||
<div class="msd-icon-example">
|
||||
<span class="msd-emoji">⚙️</span>
|
||||
<code>⚙️</code>
|
||||
<span><?php _e('Settings', 'wp-multisite-dashboard'); ?></span>
|
||||
<span><?php _e(
|
||||
"Settings",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="description">
|
||||
<strong><?php _e('Dashicons:', 'wp-multisite-dashboard'); ?></strong> <?php _e('Built into WordPress, always available. Use format:', 'wp-multisite-dashboard'); ?> <code>dashicons-icon-name</code><br>
|
||||
<strong><?php _e('Emojis:', 'wp-multisite-dashboard'); ?></strong> <?php _e('Copy and paste emoji directly. Works on all devices.', 'wp-multisite-dashboard'); ?>
|
||||
<strong><?php _e(
|
||||
"Dashicons:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></strong> <?php _e(
|
||||
"Built into WordPress, always available. Use format:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?> <code>dashicons-icon-name</code><br>
|
||||
<strong><?php _e(
|
||||
"Emojis:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></strong> <?php _e(
|
||||
"Copy and paste emoji directly. Works on all devices.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</p>
|
||||
|
||||
<p class="description">
|
||||
<?php printf(__('Find more Dashicons at %s', 'wp-multisite-dashboard'), '<a href="https://developer.wordpress.org/resource/dashicons/" target="_blank">developer.wordpress.org/resource/dashicons/</a>'); ?>
|
||||
<?php printf(
|
||||
__(
|
||||
"Find more Dashicons at %s",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
'<a href="https://developer.wordpress.org/resource/dashicons/" target="_blank">developer.wordpress.org/resource/dashicons/</a>'
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-footer">
|
||||
<button type="button" class="button button-primary" onclick="MSD.saveQuickLinks()">
|
||||
<?php _e('Save Links', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Save Links", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.hideQuickLinksModal()">
|
||||
<?php _e('Cancel', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Cancel", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,308 +0,0 @@
|
|||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$contact_info = get_site_option('msd_contact_info', [
|
||||
'name' => get_network_option(null, 'site_name'),
|
||||
'email' => get_network_option(null, 'admin_email'),
|
||||
'phone' => '',
|
||||
'website' => network_home_url(),
|
||||
'description' => 'Network Administrator Contact Information',
|
||||
'qq' => '',
|
||||
'wechat' => '',
|
||||
'whatsapp' => '',
|
||||
'telegram' => '',
|
||||
'qr_code' => ''
|
||||
]);
|
||||
?>
|
||||
|
||||
<div id="msd-contact-info-modal" class="msd-modal" style="display: none;">
|
||||
<div class="msd-modal-content">
|
||||
<div class="msd-modal-header">
|
||||
<h3><?php _e('Edit Contact Information', 'wp-multisite-dashboard'); ?></h3>
|
||||
<button type="button" class="msd-modal-close" onclick="MSD.hideContactInfoModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-body">
|
||||
<div class="msd-contact-form">
|
||||
<div class="msd-form-section">
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Organization Name:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="text" id="msd-contact-name" value="<?php echo esc_attr($contact_info['name']); ?>" placeholder="<?php esc_attr_e('Network Administrator', 'wp-multisite-dashboard'); ?>">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Email:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="email" id="msd-contact-email" value="<?php echo esc_attr($contact_info['email']); ?>" placeholder="admin@example.com">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Phone:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="text" id="msd-contact-phone" value="<?php echo esc_attr($contact_info['phone']); ?>" placeholder="+1 234 567 8900">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Website:', 'wp-multisite-dashboard'); ?></label>
|
||||
<input type="url" id="msd-contact-website" value="<?php echo esc_attr($contact_info['website']); ?>" placeholder="https://example.com">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('Description:', 'wp-multisite-dashboard'); ?></label>
|
||||
<textarea id="msd-contact-description" placeholder="<?php esc_attr_e('Brief description or role', 'wp-multisite-dashboard'); ?>"><?php echo esc_textarea($contact_info['description']); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-form-section">
|
||||
<div class="msd-form-grid">
|
||||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-admin-users"></span>
|
||||
<?php _e('QQ:', 'wp-multisite-dashboard'); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-qq" value="<?php echo esc_attr($contact_info['qq']); ?>" placeholder="1234567890">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-format-chat"></span>
|
||||
<?php _e('WeChat:', 'wp-multisite-dashboard'); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-wechat" value="<?php echo esc_attr($contact_info['wechat']); ?>" placeholder="WeChat_ID">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-form-grid">
|
||||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-smartphone"></span>
|
||||
<?php _e('WhatsApp:', 'wp-multisite-dashboard'); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-whatsapp" value="<?php echo esc_attr($contact_info['whatsapp']); ?>" placeholder="+1234567890">
|
||||
</div>
|
||||
|
||||
<div class="msd-form-field">
|
||||
<label>
|
||||
<span class="dashicons dashicons-email-alt"></span>
|
||||
<?php _e('Telegram:', 'wp-multisite-dashboard'); ?>
|
||||
</label>
|
||||
<input type="text" id="msd-contact-telegram" value="<?php echo esc_attr($contact_info['telegram']); ?>" placeholder="@username">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-form-section">
|
||||
<div class="msd-form-field">
|
||||
<label><?php _e('QR Code Image URL:', 'wp-multisite-dashboard'); ?></label>
|
||||
<div class="msd-qr-input-group">
|
||||
<input type="url" id="msd-contact-qr-code" value="<?php echo esc_attr($contact_info['qr_code']); ?>" placeholder="https://example.com/qr-code.png">
|
||||
<button type="button" class="button" onclick="MSD.selectQRImage()"><?php _e('Select Image', 'wp-multisite-dashboard'); ?></button>
|
||||
</div>
|
||||
<p class="description"><?php _e('Upload or provide URL for a QR code image (WeChat, contact info, etc.)', 'wp-multisite-dashboard'); ?></p>
|
||||
|
||||
<div id="msd-qr-preview" class="msd-qr-preview" style="<?php echo empty($contact_info['qr_code']) ? 'display: none;' : ''; ?>">
|
||||
<img src="<?php echo esc_url($contact_info['qr_code']); ?>" alt="QR Code Preview" class="msd-qr-preview-img">
|
||||
<button type="button" class="msd-qr-remove" onclick="MSD.removeQRCode()">×</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-footer">
|
||||
<button type="button" class="button button-primary" onclick="MSD.saveContactInfo()">
|
||||
<?php _e('Save Contact Info', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.hideContactInfoModal()">
|
||||
<?php _e('Cancel', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.msd-modal-intro {
|
||||
margin-bottom: 24px;
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-modal-intro p {
|
||||
margin: 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.msd-contact-form {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.msd-form-section {
|
||||
padding: 16px;
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius);
|
||||
background: var(--msd-bg-light);
|
||||
}
|
||||
|
||||
.msd-form-section h4 {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-bottom: 1px solid var(--msd-border);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.msd-form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.msd-form-field {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.msd-form-field:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.msd-form-field label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
color: var(--msd-text);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.msd-form-field label .dashicons {
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
color: var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-form-field input,
|
||||
.msd-form-field textarea {
|
||||
width: 100%;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius-small);
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-form-field input:focus,
|
||||
.msd-form-field textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--msd-primary);
|
||||
box-shadow: 0 0 0 2px rgba(34, 113, 177, 0.1);
|
||||
}
|
||||
|
||||
.msd-form-field textarea {
|
||||
min-height: 80px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.msd-qr-input-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.msd-qr-input-group input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.msd-qr-input-group .button {
|
||||
flex-shrink: 0;
|
||||
padding: 4px 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.msd-qr-preview {
|
||||
margin-top: 12px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius);
|
||||
padding: 8px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.msd-qr-preview-img {
|
||||
max-width: 120px;
|
||||
max-height: 120px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.msd-qr-remove {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--msd-danger);
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-qr-remove:hover {
|
||||
background: #c82333;
|
||||
}
|
||||
|
||||
.msd-form-field .description {
|
||||
margin: 6px 0 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--msd-text-light);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.msd-contact-qr {
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--msd-bg);
|
||||
}
|
||||
|
||||
.msd-qr-image {
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
border: 1px solid var(--msd-border);
|
||||
padding: 12px;
|
||||
background: var(--msd-bg);
|
||||
border-radius: var(--msd-radius-small);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.msd-form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.msd-qr-input-group {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.msd-modal-content {
|
||||
margin: 20px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,279 +0,0 @@
|
|||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$news_sources = get_site_option('msd_news_sources', [
|
||||
[
|
||||
'name' => 'WordPress News',
|
||||
'url' => 'https://wordpress.org/news/feed/',
|
||||
'enabled' => true
|
||||
]
|
||||
]);
|
||||
?>
|
||||
|
||||
<div id="msd-news-sources-modal" class="msd-modal" style="display: none;">
|
||||
<div class="msd-modal-content">
|
||||
<div class="msd-modal-header">
|
||||
<h3><?php _e('Configure News Sources', 'wp-multisite-dashboard'); ?></h3>
|
||||
<button type="button" class="msd-modal-close" onclick="MSD.hideNewsSourcesModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-body">
|
||||
<div id="msd-news-sources-editor">
|
||||
<?php if (!empty($news_sources)): ?>
|
||||
<?php foreach ($news_sources as $index => $source): ?>
|
||||
<div class="msd-news-source-item">
|
||||
<div class="msd-source-row">
|
||||
<input type="text"
|
||||
placeholder="<?php esc_attr_e('Source Name', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_attr($source['name']); ?>"
|
||||
class="msd-news-name"
|
||||
required>
|
||||
<input type="url"
|
||||
placeholder="<?php esc_attr_e('RSS Feed URL', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_url($source['url']); ?>"
|
||||
class="msd-news-url"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="msd-source-options">
|
||||
<label class="msd-checkbox-label">
|
||||
<input type="checkbox"
|
||||
class="msd-news-enabled"
|
||||
<?php checked(!empty($source['enabled'])); ?>>
|
||||
<?php _e('Enabled', 'wp-multisite-dashboard'); ?>
|
||||
</label>
|
||||
|
||||
<button type="button" class="msd-remove-source">
|
||||
<?php _e('Remove', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="msd-add-source-section">
|
||||
<button type="button" id="msd-add-news-source" class="button button-secondary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Add News Source', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-footer">
|
||||
<button type="button" class="button button-primary" onclick="MSD.saveNewsSources()">
|
||||
<?php _e('Save News Sources', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.hideNewsSourcesModal()">
|
||||
<?php _e('Cancel', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.msd-modal-intro {
|
||||
margin-bottom: 20px;
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-modal-intro p {
|
||||
margin: 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.msd-news-source-item {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
background: var(--msd-bg);
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius);
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-news-source-item:hover {
|
||||
border-color: var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-source-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.msd-source-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.msd-news-name,
|
||||
.msd-news-url {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius-small);
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-news-name:focus,
|
||||
.msd-news-url:focus {
|
||||
outline: none;
|
||||
border-color: var(--msd-primary);
|
||||
box-shadow: 0 0 0 2px rgba(34, 113, 177, 0.1);
|
||||
}
|
||||
|
||||
.msd-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
color: var(--msd-text);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.msd-checkbox-label input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.msd-add-source-section {
|
||||
text-align: center;
|
||||
margin: 24px 0;
|
||||
padding: 16px;
|
||||
border: 2px dashed var(--msd-border);
|
||||
border-radius: var(--msd-radius);
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-add-source-section:hover {
|
||||
border-color: var(--msd-primary);
|
||||
}
|
||||
|
||||
#msd-add-news-source {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.msd-news-help {
|
||||
margin-top: 24px;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-radius: var(--msd-radius);
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.msd-news-help h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.msd-news-help h5 {
|
||||
margin: 16px 0 8px 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.msd-rss-suggestions {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.msd-rss-suggestion {
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: white;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.msd-rss-suggestion strong {
|
||||
color: var(--msd-text);
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.msd-rss-suggestion code {
|
||||
background: #e9ecef;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 10px;
|
||||
word-break: break-all;
|
||||
grid-column: 1 / -1;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.msd-rss-desc {
|
||||
color: var(--msd-text-light);
|
||||
font-size: 11px;
|
||||
grid-column: 1 / -1;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.msd-feed-tips {
|
||||
background: white;
|
||||
padding: 12px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.msd-feed-tips ul {
|
||||
margin: 8px 0 0 0;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.msd-feed-tips li {
|
||||
font-size: 12px;
|
||||
color: var(--msd-text-light);
|
||||
line-height: 1.4;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.msd-source-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.msd-source-options {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.msd-rss-suggestion {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.msd-modal-content {
|
||||
margin: 20px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.msd-news-source-item.error {
|
||||
border-color: var(--msd-danger);
|
||||
background: #fff5f5;
|
||||
}
|
||||
|
||||
.msd-news-url.error {
|
||||
border-color: var(--msd-danger);
|
||||
}
|
||||
</style>
|
|
@ -1,356 +0,0 @@
|
|||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$quick_links = get_site_option('msd_quick_links', []);
|
||||
?>
|
||||
|
||||
<div id="msd-quick-links-modal" class="msd-modal" style="display: none;">
|
||||
<div class="msd-modal-content">
|
||||
<div class="msd-modal-header">
|
||||
<h3><?php _e('Configure Quick Links', 'wp-multisite-dashboard'); ?></h3>
|
||||
<button type="button" class="msd-modal-close" onclick="MSD.hideQuickLinksModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-body">
|
||||
<div id="msd-quick-links-editor">
|
||||
<?php if (!empty($quick_links)): ?>
|
||||
<?php foreach ($quick_links as $index => $link): ?>
|
||||
<div class="msd-link-item">
|
||||
<div class="msd-link-row">
|
||||
<input type="text"
|
||||
placeholder="<?php esc_attr_e('Link Title', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_attr($link['title']); ?>"
|
||||
class="msd-link-title"
|
||||
required>
|
||||
<input type="url"
|
||||
placeholder="https://example.com"
|
||||
value="<?php echo esc_url($link['url']); ?>"
|
||||
class="msd-link-url"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="msd-link-options">
|
||||
<input type="text"
|
||||
placeholder="<?php esc_attr_e('dashicons-admin-home or 🏠', 'wp-multisite-dashboard'); ?>"
|
||||
value="<?php echo esc_attr($link['icon']); ?>"
|
||||
class="msd-link-icon"
|
||||
title="<?php esc_attr_e('Icon (Dashicon class or emoji)', 'wp-multisite-dashboard'); ?>">
|
||||
|
||||
<label class="msd-checkbox-label">
|
||||
<input type="checkbox"
|
||||
class="msd-link-newtab"
|
||||
<?php checked(!empty($link['new_tab'])); ?>>
|
||||
<?php _e('Open in new tab', 'wp-multisite-dashboard'); ?>
|
||||
</label>
|
||||
|
||||
<button type="button" class="msd-remove-link">
|
||||
<?php _e('Remove', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="msd-add-link-section">
|
||||
<button type="button" id="msd-add-link" class="button button-secondary">
|
||||
<span class="dashicons dashicons-plus-alt"></span>
|
||||
<?php _e('Add Link', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="msd-quick-links-help">
|
||||
<h4><?php _e('Icon Options', 'wp-multisite-dashboard'); ?></h4>
|
||||
|
||||
<div class="msd-icon-types">
|
||||
<div class="msd-icon-type-section">
|
||||
<h5><?php _e('WordPress Dashicons', 'wp-multisite-dashboard'); ?></h5>
|
||||
<div class="msd-icon-examples">
|
||||
<div class="msd-icon-example">
|
||||
<span class="dashicons dashicons-admin-home"></span>
|
||||
<code>dashicons-admin-home</code>
|
||||
<span><?php _e('Home', 'wp-multisite-dashboard'); ?></span>
|
||||
</div>
|
||||
<div class="msd-icon-example">
|
||||
<span class="dashicons dashicons-chart-bar"></span>
|
||||
<code>dashicons-chart-bar</code>
|
||||
<span><?php _e('Analytics', 'wp-multisite-dashboard'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-icon-type-section">
|
||||
<h5><?php _e('Emojis', 'wp-multisite-dashboard'); ?></h5>
|
||||
<div class="msd-icon-examples">
|
||||
<div class="msd-icon-example">
|
||||
<span class="msd-emoji">🏠</span>
|
||||
<code>🏠</code>
|
||||
<span><?php _e('Home', 'wp-multisite-dashboard'); ?></span>
|
||||
</div>
|
||||
<div class="msd-icon-example">
|
||||
<span class="msd-emoji">⚙️</span>
|
||||
<code>⚙️</code>
|
||||
<span><?php _e('Settings', 'wp-multisite-dashboard'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="description">
|
||||
<strong><?php _e('Dashicons:', 'wp-multisite-dashboard'); ?></strong> <?php _e('Built into WordPress, always available. Use format:', 'wp-multisite-dashboard'); ?> <code>dashicons-icon-name</code><br>
|
||||
<strong><?php _e('Emojis:', 'wp-multisite-dashboard'); ?></strong> <?php _e('Copy and paste emoji directly. Works on all devices.', 'wp-multisite-dashboard'); ?>
|
||||
</p>
|
||||
|
||||
<p class="description">
|
||||
<?php printf(__('Find more Dashicons at %s', 'wp-multisite-dashboard'), '<a href="https://developer.wordpress.org/resource/dashicons/" target="_blank">developer.wordpress.org/resource/dashicons/</a>'); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="msd-modal-footer">
|
||||
<button type="button" class="button button-primary" onclick="MSD.saveQuickLinks()">
|
||||
<?php _e('Save Links', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.hideQuickLinksModal()">
|
||||
<?php _e('Cancel', 'wp-multisite-dashboard'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.msd-modal-intro {
|
||||
margin-bottom: 20px;
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-modal-intro p {
|
||||
margin: 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.msd-link-item {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
background: var(--msd-bg);
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius);
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-link-item:hover {
|
||||
border-color: var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-link-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.msd-link-options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.msd-link-title,
|
||||
.msd-link-url,
|
||||
.msd-link-icon {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--msd-border);
|
||||
border-radius: var(--msd-radius-small);
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-link-title:focus,
|
||||
.msd-link-url:focus,
|
||||
.msd-link-icon:focus {
|
||||
outline: none;
|
||||
border-color: var(--msd-primary);
|
||||
box-shadow: 0 0 0 2px rgba(34, 113, 177, 0.1);
|
||||
}
|
||||
|
||||
.msd-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
color: var(--msd-text);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.msd-checkbox-label input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.msd-add-link-section {
|
||||
text-align: center;
|
||||
margin: 24px 0;
|
||||
padding: 16px;
|
||||
border: 2px dashed var(--msd-border);
|
||||
border-radius: var(--msd-radius);
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.msd-add-link-section:hover {
|
||||
border-color: var(--msd-primary);
|
||||
}
|
||||
|
||||
#msd-add-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.msd-quick-links-help {
|
||||
margin-top: 24px;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-radius: var(--msd-radius);
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.msd-quick-links-help h4 {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.msd-icon-types {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.msd-icon-type-section h5 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.msd-icon-examples {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.msd-icon-example {
|
||||
display: grid;
|
||||
grid-template-columns: 24px 1fr auto;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
background: white;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.msd-icon-example .dashicons {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: var(--msd-primary);
|
||||
}
|
||||
|
||||
.msd-icon-example .msd-emoji {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.msd-icon-example code {
|
||||
background: #e9ecef;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.msd-icon-example span:last-child {
|
||||
color: var(--msd-text-light);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.msd-reorder-tip {
|
||||
margin-top: 20px;
|
||||
padding: 12px;
|
||||
background: #e7f3ff;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #2196f3;
|
||||
}
|
||||
|
||||
.msd-reorder-tip h5 {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--msd-text);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.msd-quick-links-help .description {
|
||||
margin: 12px 0 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--msd-text-light);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.msd-quick-links-help .description:last-child {
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.msd-quick-links-help a {
|
||||
color: var(--msd-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.msd-quick-links-help a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.msd-link-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.msd-link-options {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.msd-icon-examples {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.msd-modal-content {
|
||||
margin: 20px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.msd-link-item.error {
|
||||
border-color: var(--msd-danger);
|
||||
background: #fff5f5;
|
||||
}
|
||||
|
||||
.msd-link-url.error {
|
||||
border-color: var(--msd-danger);
|
||||
}
|
||||
</style>
|
|
@ -1,90 +1,159 @@
|
|||
<?php
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_GET['updated']) && $_GET['updated'] === 'true') {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' . __('Settings saved successfully!', 'wp-multisite-dashboard') . '</p></div>';
|
||||
if (isset($_GET["updated"]) && $_GET["updated"] === "true") {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' .
|
||||
__("Settings saved successfully!", "wp-multisite-dashboard") .
|
||||
"</p></div>";
|
||||
}
|
||||
|
||||
$plugin_core = WP_MSD_Plugin_Core::get_instance();
|
||||
$enabled_widgets = $plugin_core->get_enabled_widgets();
|
||||
$settings_manager = new WP_MSD_Settings_Manager();
|
||||
|
||||
$widget_options = [
|
||||
"msd_network_overview" => __("Network Overview", "wp-multisite-dashboard"),
|
||||
"msd_quick_site_management" => __(
|
||||
"Quick Site Management",
|
||||
"wp-multisite-dashboard"
|
||||
),
|
||||
"msd_storage_performance" => __("Storage Usage", "wp-multisite-dashboard"),
|
||||
"msd_server_info" => __("Server Information", "wp-multisite-dashboard"),
|
||||
"msd_quick_links" => __("Quick Links", "wp-multisite-dashboard"),
|
||||
"msd_version_info" => __("Version Information", "wp-multisite-dashboard"),
|
||||
"msd_custom_news" => __("Network News", "wp-multisite-dashboard"),
|
||||
"msd_user_management" => __("User Management", "wp-multisite-dashboard"),
|
||||
"msd_contact_info" => __("Contact Information", "wp-multisite-dashboard"),
|
||||
"msd_last_edits" => __("Recent Network Activity", "wp-multisite-dashboard"),
|
||||
"msd_todo_widget" => __("Todo List", "wp-multisite-dashboard"),
|
||||
];
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html( get_admin_page_title() ); ?>
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?>
|
||||
<span style="font-size: 13px; padding-left: 10px;">
|
||||
<?php printf( esc_html__( 'Version: %s', 'wp-multisite-dashboard' ), esc_html( WP_MSD_VERSION ) ); ?>
|
||||
<?php printf(
|
||||
esc_html__("Version: %s", "wp-multisite-dashboard"),
|
||||
esc_html(WP_MSD_VERSION)
|
||||
); ?>
|
||||
</span>
|
||||
<a href="https://wpmultisite.com/document/wp-multisite-dashboard" target="_blank" class="button button-secondary" style="margin-left: 10px;">
|
||||
<?php esc_html_e( 'Documentation', 'wp-multisite-dashboard' ); ?>
|
||||
<?php esc_html_e("Documentation", "wp-multisite-dashboard"); ?>
|
||||
</a>
|
||||
<a href="https://wpmultisite.com/support/" target="_blank" class="button button-secondary">
|
||||
<?php esc_html_e( 'Support', 'wp-multisite-dashboard' ); ?>
|
||||
<?php esc_html_e("Support", "wp-multisite-dashboard"); ?>
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<div class="msd-card">
|
||||
<h2><?php _e('Plugin Widget Configuration', 'wp-multisite-dashboard'); ?></h2>
|
||||
<p><?php _e('Enable or disable custom dashboard widgets provided by this plugin.', 'wp-multisite-dashboard'); ?></p>
|
||||
<h2><?php _e(
|
||||
"Plugin Widget Configuration",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h2>
|
||||
<p><?php _e(
|
||||
"Enable or disable custom dashboard widgets provided by this plugin.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('msd_settings', 'msd_settings_nonce'); ?>
|
||||
<?php wp_nonce_field("msd_settings", "msd_settings_nonce"); ?>
|
||||
|
||||
<div class="msd-settings-grid">
|
||||
<?php foreach ($widget_options as $widget_id => $widget_name): ?>
|
||||
<?php foreach (
|
||||
$widget_options
|
||||
as $widget_id => $widget_name
|
||||
): ?>
|
||||
<div class="msd-widget-toggle">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="widgets[<?php echo esc_attr($widget_id); ?>]"
|
||||
name="widgets[<?php echo esc_attr(
|
||||
$widget_id
|
||||
); ?>]"
|
||||
value="1"
|
||||
<?php checked(!empty($enabled_widgets[$widget_id])); ?>
|
||||
<?php checked(
|
||||
!empty($enabled_widgets[$widget_id])
|
||||
); ?>
|
||||
/>
|
||||
<?php echo esc_html($widget_name); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php echo $settings_manager->get_widget_description($widget_id); ?>
|
||||
<?php echo $settings_manager->get_widget_description(
|
||||
$widget_id
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<h3><?php _e('System & Third-Party Widgets', 'wp-multisite-dashboard'); ?></h3>
|
||||
<p><?php _e('Control the display of WordPress system widgets and widgets from other plugins.', 'wp-multisite-dashboard'); ?></p>
|
||||
<h3><?php _e(
|
||||
"System & Third-Party Widgets",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h3>
|
||||
<p><?php _e(
|
||||
"Control the display of WordPress system widgets and widgets from other plugins.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
|
||||
<?php
|
||||
$available_widgets = $settings_manager->get_available_system_widgets();
|
||||
$disabled_widgets = get_site_option('msd_disabled_system_widgets', []);
|
||||
$disabled_widgets = get_site_option(
|
||||
"msd_disabled_system_widgets",
|
||||
[]
|
||||
);
|
||||
|
||||
if (!empty($available_widgets)):
|
||||
?>
|
||||
if (!empty($available_widgets)): ?>
|
||||
<div class="msd-system-widgets-grid">
|
||||
<?php
|
||||
$system_widgets = array_filter($available_widgets, function($widget) {
|
||||
return $widget['is_system'];
|
||||
});
|
||||
$system_widgets = array_filter(
|
||||
$available_widgets,
|
||||
function ($widget) {
|
||||
return $widget["is_system"] ?? false;
|
||||
}
|
||||
);
|
||||
|
||||
$third_party_widgets = array_filter($available_widgets, function($widget) {
|
||||
return !$widget['is_system'] && !$widget['is_custom'];
|
||||
});
|
||||
$third_party_widgets = array_filter(
|
||||
$available_widgets,
|
||||
function ($widget) {
|
||||
return !($widget["is_system"] ?? false) &&
|
||||
!($widget["is_custom"] ?? false);
|
||||
}
|
||||
);
|
||||
?>
|
||||
|
||||
<?php if (!empty($system_widgets)): ?>
|
||||
<div class="msd-widget-section">
|
||||
<h4><?php _e('WordPress System Widgets', 'wp-multisite-dashboard'); ?></h4>
|
||||
<?php foreach ($system_widgets as $widget_id => $widget_data): ?>
|
||||
<h4><?php _e(
|
||||
"WordPress System Widgets",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h4>
|
||||
<?php foreach (
|
||||
$system_widgets
|
||||
as $widget_id => $widget_data
|
||||
): ?>
|
||||
<div class="msd-widget-toggle">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="system_widgets[<?php echo esc_attr($widget_id); ?>]"
|
||||
name="system_widgets[<?php echo esc_attr(
|
||||
$widget_id
|
||||
); ?>]"
|
||||
value="1"
|
||||
<?php checked(!in_array($widget_id, $disabled_widgets)); ?>
|
||||
<?php checked(
|
||||
!in_array(
|
||||
$widget_id,
|
||||
$disabled_widgets
|
||||
)
|
||||
); ?>
|
||||
/>
|
||||
<?php echo esc_html($widget_data['title']); ?>
|
||||
<span class="msd-widget-meta">(<?php echo esc_html($widget_data['context']); ?>)</span>
|
||||
<?php echo esc_html(
|
||||
$widget_data["title"]
|
||||
); ?>
|
||||
<span class="msd-widget-meta">(<?php echo esc_html(
|
||||
$widget_data["context"]
|
||||
); ?>)</span>
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
@ -93,86 +162,171 @@ $settings_manager = new WP_MSD_Settings_Manager();
|
|||
|
||||
<?php if (!empty($third_party_widgets)): ?>
|
||||
<div class="msd-widget-section">
|
||||
<h4><?php _e('Third-Party Plugin Widgets', 'wp-multisite-dashboard'); ?></h4>
|
||||
<?php foreach ($third_party_widgets as $widget_id => $widget_data): ?>
|
||||
<h4><?php _e(
|
||||
"Third-Party Plugin Widgets",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h4>
|
||||
<?php foreach (
|
||||
$third_party_widgets
|
||||
as $widget_id => $widget_data
|
||||
): ?>
|
||||
<div class="msd-widget-toggle">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="system_widgets[<?php echo esc_attr($widget_id); ?>]"
|
||||
name="system_widgets[<?php echo esc_attr(
|
||||
$widget_id
|
||||
); ?>]"
|
||||
value="1"
|
||||
<?php checked(!in_array($widget_id, $disabled_widgets)); ?>
|
||||
<?php checked(
|
||||
!in_array(
|
||||
$widget_id,
|
||||
$disabled_widgets
|
||||
)
|
||||
); ?>
|
||||
/>
|
||||
<?php echo esc_html($widget_data['title']); ?>
|
||||
<span class="msd-widget-meta">(<?php echo esc_html($widget_data['context']); ?>)</span>
|
||||
<?php echo esc_html(
|
||||
$widget_data["title"]
|
||||
); ?>
|
||||
<span class="msd-widget-meta">(<?php echo esc_html(
|
||||
$widget_data["context"]
|
||||
); ?>)</span>
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($third_party_widgets)): ?>
|
||||
<div class="msd-widget-section">
|
||||
<h4><?php _e('Third-Party Plugin Widgets', 'wp-multisite-dashboard'); ?></h4>
|
||||
<h4><?php _e(
|
||||
"Third-Party Plugin Widgets",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></h4>
|
||||
<div class="msd-no-third-party">
|
||||
<p><?php _e('No third-party widgets detected yet.', 'wp-multisite-dashboard'); ?></p>
|
||||
<p class="description"><?php _e('Third-party widgets are automatically detected when you visit the network dashboard. If you have plugins that add dashboard widgets, visit the dashboard first, then return here to see them.', 'wp-multisite-dashboard'); ?></p>
|
||||
<a href="<?php echo network_admin_url(); ?>" class="button button-secondary">
|
||||
<?php _e('Visit Network Dashboard', 'wp-multisite-dashboard'); ?>
|
||||
</a>
|
||||
<p><?php _e(
|
||||
"No third-party widgets detected yet.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
<p class="description"><?php _e(
|
||||
"Third-party widgets are automatically detected when you visit the network dashboard. If you have plugins that add dashboard widgets, visit the dashboard first, then return here to see them.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
<div style="margin: 15px 0;">
|
||||
<a href="<?php echo network_admin_url(); ?>" class="button button-secondary">
|
||||
<?php _e(
|
||||
"Visit Network Dashboard",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</a>
|
||||
<button type="button" class="button" onclick="MSD.clearWidgetCache()">
|
||||
<?php _e(
|
||||
"Refresh Widget Detection",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="msd-no-widgets">
|
||||
<p><?php _e('No system widgets found.', 'wp-multisite-dashboard'); ?></p>
|
||||
<p><?php _e(
|
||||
"No system widgets found.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
<p><?php _e(
|
||||
"Visit the network dashboard to detect available widgets.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
<div style="margin: 15px 0;">
|
||||
<a href="<?php echo network_admin_url(); ?>" class="button button-secondary">
|
||||
<?php _e(
|
||||
"Visit Network Dashboard",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</a>
|
||||
<button type="button" class="button" onclick="MSD.clearWidgetCache()">
|
||||
<?php _e(
|
||||
"Refresh Widget Detection",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif;
|
||||
?>
|
||||
|
||||
<p class="submit">
|
||||
<?php submit_button(__('Save Widget Settings', 'wp-multisite-dashboard'), 'primary', 'submit', false); ?>
|
||||
<?php submit_button(
|
||||
__("Save Widget Settings", "wp-multisite-dashboard"),
|
||||
"primary",
|
||||
"submit",
|
||||
false
|
||||
); ?>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="msd-card">
|
||||
<h2><?php _e('Cache Management', 'wp-multisite-dashboard'); ?></h2>
|
||||
<p><?php _e('Clear cached data to refresh dashboard widgets.', 'wp-multisite-dashboard'); ?></p>
|
||||
<h2><?php _e("Cache Management", "wp-multisite-dashboard"); ?></h2>
|
||||
<p><?php _e(
|
||||
"Clear cached data to refresh dashboard widgets.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
|
||||
<div class="msd-cache-actions">
|
||||
<button type="button" class="button" onclick="MSD.clearCache('all')">
|
||||
↻
|
||||
<?php _e('Clear All Caches', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Clear All Caches", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.clearCache('network')">
|
||||
<span class="dashicons dashicons-admin-multisite"></span>
|
||||
<?php _e('Clear Network Data', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Clear Network Data", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
<button type="button" class="button" onclick="MSD.clearWidgetCache()">
|
||||
<span class="dashicons dashicons-dashboard"></span>
|
||||
<?php _e('Clear Widget Cache', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e("Clear Widget Cache", "wp-multisite-dashboard"); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="description">
|
||||
<?php _e('Clearing caches will force the dashboard widgets to reload fresh data on the next page visit. Widget cache contains the list of detected third-party widgets.', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"Clearing caches will force the dashboard widgets to reload fresh data on the next page visit. Widget cache contains the list of detected third-party widgets.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="msd-card">
|
||||
<h2><?php _e('Plugin Information', 'wp-multisite-dashboard'); ?></h2>
|
||||
<p><?php _e('Current plugin status and update information.', 'wp-multisite-dashboard'); ?></p>
|
||||
<h2><?php _e("Plugin Information", "wp-multisite-dashboard"); ?></h2>
|
||||
<p><?php _e(
|
||||
"Current plugin status and update information.",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></p>
|
||||
|
||||
<div class="msd-plugin-info">
|
||||
<div class="msd-info-row">
|
||||
<span class="msd-info-label"><?php _e('Current Version:', 'wp-multisite-dashboard'); ?></span>
|
||||
<span class="msd-info-value"><?php echo esc_html(WP_MSD_VERSION); ?></span>
|
||||
<span class="msd-info-label"><?php _e(
|
||||
"Current Version:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
<span class="msd-info-value"><?php echo esc_html(
|
||||
WP_MSD_VERSION
|
||||
); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="msd-info-row">
|
||||
<span class="msd-info-label"><?php _e('Update Status:', 'wp-multisite-dashboard'); ?></span>
|
||||
<span class="msd-info-label"><?php _e(
|
||||
"Update Status:",
|
||||
"wp-multisite-dashboard"
|
||||
); ?></span>
|
||||
<span class="msd-info-value" id="msd-update-status">
|
||||
<button type="button" class="button button-small" onclick="MSD.checkForUpdates()">
|
||||
<?php _e('Check for Updates', 'wp-multisite-dashboard'); ?>
|
||||
<?php _e(
|
||||
"Check for Updates",
|
||||
"wp-multisite-dashboard"
|
||||
); ?>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -375,89 +529,3 @@ $settings_manager = new WP_MSD_Settings_Manager();
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
'use strict';
|
||||
|
||||
// 确保全局 MSD 对象存在
|
||||
window.MSD = window.MSD || {};
|
||||
|
||||
// 清除缓存功能
|
||||
window.MSD.clearCache = function(type) {
|
||||
if (!confirm('Are you sure you want to clear the cache?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.post(msdAjax.ajaxurl, {
|
||||
action: 'msd_clear_cache',
|
||||
cache_type: type,
|
||||
nonce: msdAjax.nonce
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
alert('Cache cleared successfully!');
|
||||
} else {
|
||||
alert('Failed to clear cache: ' + (response.data || 'Unknown error'));
|
||||
}
|
||||
}).fail(function() {
|
||||
alert('Failed to clear cache due to network error.');
|
||||
});
|
||||
};
|
||||
|
||||
// 检查更新功能
|
||||
window.MSD.checkForUpdates = function() {
|
||||
var $status = $('#msd-update-status');
|
||||
var $button = $status.find('button');
|
||||
|
||||
$button.prop('disabled', true).text('Checking...');
|
||||
|
||||
$.post(msdAjax.ajaxurl, {
|
||||
action: 'msd_check_plugin_update',
|
||||
nonce: msdAjax.nonce
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
if (response.data.version) {
|
||||
$status.html('<span class="msd-update-available">Version ' + response.data.version + ' available!</span>');
|
||||
if (response.data.details_url) {
|
||||
$status.append(' <a href="' + response.data.details_url + '" target="_blank">View Details</a>');
|
||||
}
|
||||
} else {
|
||||
$status.html('<span class="msd-update-current">Up to date</span>');
|
||||
}
|
||||
} else {
|
||||
$button.prop('disabled', false).text('Check for Updates');
|
||||
alert('Failed to check for updates: ' + (response.data || 'Unknown error'));
|
||||
}
|
||||
}).fail(function() {
|
||||
$button.prop('disabled', false).text('Check for Updates');
|
||||
alert('Failed to check for updates due to network error.');
|
||||
});
|
||||
};
|
||||
|
||||
// 清除小部件缓存功能
|
||||
window.MSD.clearWidgetCache = function() {
|
||||
if (!confirm('Are you sure you want to clear the widget cache? This will refresh the list of detected widgets.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.post(msdAjax.ajaxurl, {
|
||||
action: 'msd_clear_widget_cache',
|
||||
nonce: msdAjax.nonce
|
||||
}, function(response) {
|
||||
if (response.success) {
|
||||
alert('Widget cache cleared successfully! Please reload the page to see updated widgets.');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Failed to clear widget cache: ' + (response.data || 'Unknown error'));
|
||||
}
|
||||
}).fail(function() {
|
||||
alert('Failed to clear widget cache due to network error.');
|
||||
});
|
||||
};
|
||||
|
||||
// 调试信息
|
||||
console.log('MSD Settings loaded with functions:', Object.keys(window.MSD));
|
||||
console.log('msdAjax object:', msdAjax);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -3,72 +3,91 @@
|
|||
* Plugin Name: WP Multisite Dashboard
|
||||
* Plugin URI: https://wpmultisite.com/plugins/wp-multisite-dashboard
|
||||
* Description: Essential dashboard widgets for WordPress multisite administrators
|
||||
* Version: 1.2.0
|
||||
* Version: 1.2.2
|
||||
* Author: WPMultisite.com
|
||||
* Author URI: https://WPMultisite.com
|
||||
* License: GPLv2+
|
||||
* Text Domain: wp-multisite-dashboard
|
||||
* Domain Path: /languages
|
||||
* Requires PHP: 7.4
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
}
|
||||
|
||||
define('WP_MSD_VERSION', '1.2.0');
|
||||
define('WP_MSD_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
define('WP_MSD_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||
define("WP_MSD_VERSION", "1.2.2");
|
||||
define("WP_MSD_PLUGIN_DIR", plugin_dir_path(__FILE__));
|
||||
define("WP_MSD_PLUGIN_URL", plugin_dir_url(__FILE__));
|
||||
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-helpers.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-network-data.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-user-manager.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-ajax-handler.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-admin-interface.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-settings-manager.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . 'includes/class-plugin-core.php';
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-helpers.php";
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-network-data.php";
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-user-manager.php";
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-ajax-handler.php";
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-admin-interface.php";
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-settings-manager.php";
|
||||
require_once WP_MSD_PLUGIN_DIR . "includes/class-plugin-core.php";
|
||||
|
||||
function wp_msd_init() {
|
||||
function wp_msd_init()
|
||||
{
|
||||
if (!is_multisite()) {
|
||||
add_action('admin_notices', 'wp_msd_multisite_required_notice');
|
||||
add_action("admin_notices", "wp_msd_multisite_required_notice");
|
||||
return;
|
||||
}
|
||||
|
||||
WP_MSD_Plugin_Core::get_instance();
|
||||
}
|
||||
|
||||
function wp_msd_multisite_load_textdomain() {
|
||||
load_plugin_textdomain('wp-multisite-dashboard', false, dirname(plugin_basename(__FILE__)) . '/languages');
|
||||
function wp_msd_multisite_load_textdomain()
|
||||
{
|
||||
$plugin_rel_path = dirname(plugin_basename(__FILE__)) . "/languages/";
|
||||
load_plugin_textdomain("wp-multisite-dashboard", false, $plugin_rel_path);
|
||||
}
|
||||
add_action('plugins_loaded', 'wp_msd_multisite_load_textdomain');
|
||||
add_action("plugins_loaded", "wp_msd_multisite_load_textdomain");
|
||||
|
||||
|
||||
function wp_msd_multisite_required_notice() {
|
||||
function wp_msd_multisite_required_notice()
|
||||
{
|
||||
echo '<div class="notice notice-error"><p>';
|
||||
echo __('WP Multisite Dashboard requires WordPress Multisite to be enabled.', 'wp-multisite-dashboard');
|
||||
echo '</p></div>';
|
||||
echo __(
|
||||
"WP Multisite Dashboard requires WordPress Multisite to be enabled.",
|
||||
"wp-multisite-dashboard"
|
||||
);
|
||||
echo "</p></div>";
|
||||
}
|
||||
|
||||
register_activation_hook(__FILE__, 'wp_msd_activation');
|
||||
function wp_msd_activation() {
|
||||
register_activation_hook(__FILE__, "wp_msd_activation");
|
||||
function wp_msd_activation()
|
||||
{
|
||||
if (!is_multisite()) {
|
||||
deactivate_plugins(plugin_basename(__FILE__));
|
||||
wp_die(__('This plugin requires WordPress Multisite to be enabled.', 'wp-multisite-dashboard'));
|
||||
wp_die(
|
||||
__(
|
||||
"This plugin requires WordPress Multisite to be enabled.",
|
||||
"wp-multisite-dashboard"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$network_data = new WP_MSD_Network_Data();
|
||||
$network_data->create_activity_log_table();
|
||||
|
||||
set_site_transient('msd_activation_notice', true, 30);
|
||||
set_site_transient("msd_activation_notice", true, 30);
|
||||
}
|
||||
|
||||
add_action('network_admin_notices', 'wp_msd_activation_notice');
|
||||
function wp_msd_activation_notice() {
|
||||
if (get_site_transient('msd_activation_notice')) {
|
||||
add_action("network_admin_notices", "wp_msd_activation_notice");
|
||||
function wp_msd_activation_notice()
|
||||
{
|
||||
if (get_site_transient("msd_activation_notice")) {
|
||||
echo '<div class="notice notice-success is-dismissible">';
|
||||
echo '<p>' . __('WP Multisite Dashboard has been activated successfully!', 'wp-multisite-dashboard') . '</p>';
|
||||
echo '</div>';
|
||||
delete_site_transient('msd_activation_notice');
|
||||
echo "<p>" .
|
||||
__(
|
||||
"WP Multisite Dashboard has been activated successfully!",
|
||||
"wp-multisite-dashboard"
|
||||
) .
|
||||
"</p>";
|
||||
echo "</div>";
|
||||
delete_site_transient("msd_activation_notice");
|
||||
}
|
||||
}
|
||||
|
||||
add_action('plugins_loaded', 'wp_msd_init');
|
||||
add_action("plugins_loaded", "wp_msd_init");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue