diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..797468f Binary files /dev/null and b/.DS_Store differ diff --git a/assets/dashboard-core.js b/assets/dashboard-core.js new file mode 100644 index 0000000..01f7a35 --- /dev/null +++ b/assets/dashboard-core.js @@ -0,0 +1,235 @@ +jQuery(document).ready(function($) { + 'use strict'; + + const MSD_Core = { + refreshInterval: null, + refreshRate: 300000, + isRefreshing: false, + retryCount: 0, + maxRetries: 3, + + init() { + this.bindEvents(); + this.startAutoRefresh(); + this.setupErrorHandling(); + }, + + 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 = $(`

${this.escapeHtml(message)}

`); + + 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.MSD_Core = MSD_Core; + MSD_Core.init(); + + $('head').append(` + + `); +}); diff --git a/assets/dashboard-modals.js b/assets/dashboard-modals.js new file mode 100644 index 0000000..d6fa8c5 --- /dev/null +++ b/assets/dashboard-modals.js @@ -0,0 +1,376 @@ +jQuery(document).ready(function($) { + 'use strict'; + + const MSD_Modals = { + init() { + this.bindEvents(); + // 延迟初始化 sortable,等待页面完全加载 + $(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() { + // 使用延迟初始化,确保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); + }); + }, + + saveQuickLinksOrder() { + const order = []; + $('#msd-sortable-links .msd-quick-link-item').each(function() { + const index = $(this).data('index'); + if (index !== undefined) { + order.push(index); + } + }); + + 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'); + } + ); + } + }, + + handleModalClose(e) { + if (e.target === e.currentTarget || $(e.target).hasClass('msd-modal-close')) { + this.hideQuickLinksModal(); + this.hideNewsSourcesModal(); + this.hideContactInfoModal(); + } + }, + + showQuickLinksModal() { + $('#msd-quick-links-modal').fadeIn(200); + $('body').addClass('modal-open'); + }, + + hideQuickLinksModal() { + $('#msd-quick-links-modal').fadeOut(200); + $('body').removeClass('modal-open'); + }, + + showNewsSourcesModal() { + $('#msd-news-sources-modal').fadeIn(200); + $('body').addClass('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 = ` + + `; + $('#msd-quick-links-editor').append(html); + }, + + removeQuickLinkRow(e) { + $(e.currentTarget).closest('.msd-link-item').fadeOut(200, function() { + $(this).remove(); + }); + }, + + addNewsSourceRow() { + const html = ` +
+
+ + +
+
+ + +
+
+ `; + $('#msd-news-sources-editor').append(html); + }, + + removeNewsSourceRow(e) { + $(e.currentTarget).closest('.msd-news-source-item').fadeOut(200, function() { + $(this).remove(); + }); + }, + + saveQuickLinks() { + const links = []; + let hasErrors = false; + + // Clear previous errors + $('.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'); + + 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; + } + } + }; + + window.MSD_Modals = MSD_Modals; + MSD_Modals.init(); +}); diff --git a/assets/dashboard.js b/assets/dashboard-widgets.js similarity index 58% rename from assets/dashboard.js rename to assets/dashboard-widgets.js index dd35239..b6670e7 100644 --- a/assets/dashboard.js +++ b/assets/dashboard-widgets.js @@ -1,113 +1,30 @@ jQuery(document).ready(function($) { 'use strict'; - const MSD = { - refreshInterval: null, - refreshRate: 300000, - isRefreshing: false, - retryCount: 0, - maxRetries: 3, - + const MSD_Widgets = { init() { this.loadAllWidgets(); this.bindEvents(); - this.startAutoRefresh(); - this.setupErrorHandling(); - this.initSortable(); }, bindEvents() { $(document) - .on('click', '.msd-refresh-btn', this.handleRefreshClick.bind(this)) - .on('click', '.msd-btn-primary, .msd-btn-secondary', this.handleButtonClick.bind(this)) .on('click', '.msd-user-action-btn', this.handleUserAction.bind(this)) - .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)) .on('click', '.msd-todo-add-btn', this.showTodoForm.bind(this)) .on('click', '.msd-todo-checkbox', this.toggleTodoComplete.bind(this)) .on('click', '.msd-todo-edit', this.editTodo.bind(this)) .on('click', '.msd-todo-delete', this.deleteTodo.bind(this)) .on('click', '.msd-todo-save', this.saveTodo.bind(this)) .on('click', '.msd-todo-cancel', this.cancelTodoForm.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) - }; - - $(window).on('beforeunload', () => { - if (this.refreshInterval) { - clearInterval(this.refreshInterval); - } - }); - }, - - initSortable() { - if ($.ui && $.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(); - } - }); - } - }, - - saveQuickLinksOrder() { - const order = []; - $('#msd-sortable-links .msd-quick-link-item').each(function() { - const index = $(this).data('index'); - if (index !== undefined) { - order.push(index); - } - }); - - if (order.length > 0) { - this.makeAjaxRequest('msd_reorder_quick_links', { order }, - () => { - this.showNotice(msdAjax.strings.save_success, 'success', 2000); - }, - () => { - this.showNotice('Failed to save order', 'error'); - } - ); - } - }, - - 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'); - } - }); }, loadAllWidgets() { - if (this.isRefreshing) return; + if (window.MSD_Core && window.MSD_Core.isRefreshing) return; + + if (window.MSD_Core) { + window.MSD_Core.isRefreshing = true; + } - this.isRefreshing = true; const widgets = ['network_overview', 'site_list', 'storage_data', 'version_info', 'custom_news', 'network_settings', 'user_management', 'last_edits', 'todo_items']; widgets.forEach(widget => { @@ -115,7 +32,9 @@ jQuery(document).ready(function($) { }); setTimeout(() => { - this.isRefreshing = false; + if (window.MSD_Core) { + window.MSD_Core.isRefreshing = false; + } }, 1000); }, @@ -138,12 +57,16 @@ jQuery(document).ready(function($) { const action = actionMap[widgetType]; if (!action) return; - this.makeAjaxRequest(action, {}, (response) => { - this.renderWidget(widgetType, $container, response.data); - this.retryCount = 0; - }, (error) => { - this.handleWidgetError($container, error, widgetType); - }); + if (window.MSD_Core) { + window.MSD_Core.makeAjaxRequest(action, {}, (response) => { + this.renderWidget(widgetType, $container, response.data); + if (window.MSD_Core) { + window.MSD_Core.retryCount = 0; + } + }, (error) => { + this.handleWidgetError($container, error, widgetType); + }); + } }, renderWidget(widgetType, $container, data) { @@ -166,177 +89,6 @@ jQuery(document).ready(function($) { } }, - renderTodoItems($container, todos) { - let html = ` - - -
-
-
-
- - ${todos.length} total -
-
- - ${todos.filter(t => t.completed).length} done -
-
- -
- `; - - if (todos.length === 0) { - html += ` -
-

No todos yet. Click "Add Todo" to get started!

-
- `; - } else { - html += '
'; - todos.forEach(todo => { - const completedClass = todo.completed ? 'completed' : ''; - html += ` -
- -
-
${this.escapeHtml(todo.title)}
- ${todo.description ? `
${this.escapeHtml(todo.description)}
` : ''} -
- ${todo.priority} - ${todo.created_at_human} -
-
-
- - -
-
- `; - }); - html += '
'; - } - - html += ` -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- `; - - $container.html(html); - }, - - showTodoForm() { - $('#msd-todo-form').addClass('active'); - $('#msd-todo-title').focus(); - }, - - cancelTodoForm() { - $('#msd-todo-form').removeClass('active'); - this.clearTodoForm(); - }, - - clearTodoForm() { - $('#msd-todo-title').val(''); - $('#msd-todo-description').val(''); - $('#msd-todo-priority').val('medium'); - $('#msd-todo-form').removeData('edit-id'); - }, - - saveTodo() { - const title = $('#msd-todo-title').val().trim(); - if (!title) { - this.showNotice('Title is required', 'error'); - return; - } - - const data = { - title: title, - description: $('#msd-todo-description').val().trim(), - priority: $('#msd-todo-priority').val() - }; - - const editId = $('#msd-todo-form').data('edit-id'); - const action = editId ? 'msd_update_todo_item' : 'msd_save_todo_item'; - - if (editId) { - data.id = editId; - } - - this.makeAjaxRequest(action, data, (response) => { - this.showNotice(response.data.message, 'success'); - this.cancelTodoForm(); - this.loadWidget('todo_items'); - }, (error) => { - this.showNotice(error || 'Failed to save todo', 'error'); - }); - }, - - editTodo(e) { - const $item = $(e.currentTarget).closest('.msd-todo-item'); - const id = $item.data('id'); - const title = $item.find('.msd-todo-title').text(); - const description = $item.find('.msd-todo-description').text(); - - $('#msd-todo-title').val(title); - $('#msd-todo-description').val(description); - $('#msd-todo-form').data('edit-id', id).addClass('active'); - $('#msd-todo-title').focus(); - }, - - deleteTodo(e) { - if (!confirm(msdAjax.strings.confirm_delete)) { - return; - } - - const $item = $(e.currentTarget).closest('.msd-todo-item'); - const id = $item.data('id'); - - this.makeAjaxRequest('msd_delete_todo_item', { id }, (response) => { - this.showNotice(response.data.message, 'success'); - this.loadWidget('todo_items'); - }, (error) => { - this.showNotice(error || 'Failed to delete todo', 'error'); - }); - }, - - toggleTodoComplete(e) { - const $item = $(e.currentTarget).closest('.msd-todo-item'); - const id = $item.data('id'); - - this.makeAjaxRequest('msd_toggle_todo_complete', { id }, (response) => { - this.loadWidget('todo_items'); - }, (error) => { - this.showNotice(error || 'Failed to update todo', 'error'); - }); - }, - renderNetworkOverview($container, data) { const html = ` '; - - if (!activities || activities.length === 0) { - html += '

No recent network activity found.

'; - } else { - html += '
'; - activities.forEach(activity => { - const truncatedContent = activity.content ? this.truncateText(activity.content, 30) : ''; - html += ` -
- -
- ${this.escapeHtml(activity.site_name)} - ${activity.date_human} -
- ${truncatedContent ? `

${this.escapeHtml(truncatedContent)}

` : ''} -
- Edit - View -
-
- `; - }); - html += '
'; - } - - $container.html(html); + // 重新初始化 sortable 功能 + setTimeout(() => { + if (window.MSD_Modals && window.MSD_Modals.initSortable) { + window.MSD_Modals.initSortable(); + } + }, 100); }, renderQuickSites($container, sites) { @@ -503,136 +227,6 @@ jQuery(document).ready(function($) { $container.html(html); }, - getRegistrationLabel(registration) { - const labels = { - 'none': 'Disabled', - 'user': 'Users Only', - 'blog': 'Sites Only', - 'all': 'Users & Sites' - }; - return labels[registration] || 'Unknown'; - }, - - renderUserManagement($container, data) { - let html = ` - - -
-
- ${data.total_users || 0} users (${data.super_admin_count || 0} admins) - ${data.registration_status?.description || 'Unknown'} -
- -
- `; - - if (data.recent_registrations && data.recent_registrations.length > 0) { - data.recent_registrations.slice(0, 5).forEach(user => { - const statusClass = this.getUserStatusClass(user.status); - html += ` -
- ${this.escapeHtml(user.display_name)} -
-
${this.escapeHtml(user.display_name)}
- -
- -
- `; - }); - } else { - html += '
No recent registrations
'; - } - - html += '
'; - - if (data.pending_activations && data.pending_activations.length > 0) { - html += ` -
-
${data.pending_activations.length} pending activation(s)
- `; - - data.pending_activations.slice(0, 3).forEach(signup => { - html += ` -
-
${this.escapeHtml(signup.user_email)}
- Activate -
- `; - }); - - html += '
'; - } - - html += '
'; - - $container.html(html); - }, - - getDefaultAvatar() { - return 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48Y2lyY2xlIGN4PSIyMCIgY3k9IjIwIiByPSIyMCIgZmlsbD0iI2Y2ZjdmNyIgc3Ryb2tlPSIjZGRkIi8+PGNpcmNsZSBjeD0iMjAiIGN5PSIxNSIgcj0iNiIgZmlsbD0iIzk5OSIvPjxlbGxpcHNlIGN4PSIyMCIgY3k9IjMzIiByeD0iMTAiIHJ5PSI3IiBmaWxsPSIjOTk5Ii8+PC9zdmc+'; - }, - - 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'; - }, - - handleUserAction(e) { - e.preventDefault(); - const $btn = $(e.currentTarget); - const action = $btn.data('action'); - const userId = $btn.data('user-id'); - - if (!action || !userId) { - this.showNotice('Invalid action or user ID', 'error'); - return; - } - - if (!confirm('Are you sure you want to perform this action?')) { - return; - } - - $btn.prop('disabled', true).text('Processing...'); - - this.makeAjaxRequest('msd_manage_user_action', { - user_action: action, - user_id: userId - }, (response) => { - this.showNotice(response.data.message || 'Action completed successfully', 'success'); - this.loadWidget('user_management'); - }, (error) => { - this.showNotice(error || 'Action failed', 'error'); - }).always(() => { - $btn.prop('disabled', false).text($btn.data('original-text') || 'Action'); - }); - }, - renderVersionInfo($container, data) { let html = ` - if (diffDays === 1) { - return 'Yesterday'; - } else if (diffDays < 7) { - return `${diffDays} days ago`; - } else { - return date.toLocaleDateString(); - } - } catch (e) { - return ''; - } - }, +
+
+ ${data.total_users || 0} users (${data.super_admin_count || 0} admins) + ${data.registration_status?.description || 'Unknown'} +
- getDefaultFavicon() { - return 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbGw9IiNmMGYwZjAiLz48dGV4dCB4PSI1MCUiIHk9IjUwJSIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmaWxsPSIjOTk5IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iMC4zNWVtIj5TPC90ZXh0Pjwvc3ZnPg=='; - }, +
+ `; - startAutoRefresh() { - this.refreshInterval = setInterval(() => { - if (!this.isRefreshing && document.visibilityState === 'visible') { - this.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) { - this.loadWidget(widgetType); - this.showNotice(msdAjax.strings.refresh_success, 'success', 2000); + if (data.recent_registrations && data.recent_registrations.length > 0) { + data.recent_registrations.slice(0, 5).forEach(user => { + const statusClass = this.getUserStatusClass(user.status); + html += ` +
+ ${this.escapeHtml(user.display_name)} +
+
${this.escapeHtml(user.display_name)}
+ +
+ +
+ `; + }); } else { - this.loadAllWidgets(); - this.showNotice(msdAjax.strings.refresh_success, 'success', 2000); + html += '
No recent registrations
'; } - }, - handleButtonClick(e) { - const $btn = $(e.currentTarget); - const url = $btn.attr('href'); + html += '
'; - if (url && url !== '#' && !url.startsWith('javascript:')) { - if ($btn.hasClass('msd-btn-primary')) { - window.open(url, '_blank', 'noopener,noreferrer'); - e.preventDefault(); - } + if (data.pending_activations && data.pending_activations.length > 0) { + html += ` +
+
${data.pending_activations.length} pending activation(s)
+ `; + + data.pending_activations.slice(0, 3).forEach(signup => { + html += ` +
+
${this.escapeHtml(signup.user_email)}
+ Activate +
+ `; + }); + + html += '
'; } + + html += '
'; + + $container.html(html); }, - handleModalClose(e) { - if (e.target === e.currentTarget || $(e.target).hasClass('msd-modal-close')) { - this.hideQuickLinksModal(); - this.hideNewsSourcesModal(); - this.hideContactInfoModal(); + renderLastEdits($container, activities) { + let html = ''; + + if (!activities || activities.length === 0) { + html += '

No recent network activity found.

'; + } else { + html += '
'; + activities.forEach(activity => { + const truncatedContent = activity.content ? this.truncateText(activity.content, 30) : ''; + html += ` +
+ +
+ ${this.escapeHtml(activity.site_name)} + ${activity.date_human} +
+ ${truncatedContent ? `

${this.escapeHtml(truncatedContent)}

` : ''} +
+ Edit + View +
+
+ `; + }); + html += '
'; } + + $container.html(html); }, - showQuickLinksModal() { - $('#msd-quick-links-modal').fadeIn(200); - $('body').addClass('modal-open'); - }, + renderTodoItems($container, todos) { + let html = ` + - hideQuickLinksModal() { - $('#msd-quick-links-modal').fadeOut(200); - $('body').removeClass('modal-open'); - }, - - showNewsSourcesModal() { - $('#msd-news-sources-modal').fadeIn(200); - $('body').addClass('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 = ` - -
- 👥 - 👥 - -
-
- 📊 - 📊 - -
-
- 📧 - 📧 - -
-
- 🔗 - 🔗 - -
-
-
-

-
-

dashicons-icon-name
diff --git a/templates/settings-page.php b/templates/settings-page.php index a185a4f..600eda8 100644 --- a/templates/settings-page.php +++ b/templates/settings-page.php @@ -6,6 +6,10 @@ if (!defined('ABSPATH')) { if (isset($_GET['updated']) && $_GET['updated'] === 'true') { echo '

' . __('Settings saved successfully!', 'wp-multisite-dashboard') . '

'; } + +$plugin_core = WP_MSD_Plugin_Core::get_instance(); +$enabled_widgets = $plugin_core->get_enabled_widgets(); +$settings_manager = new WP_MSD_Settings_Manager(); ?>
@@ -22,8 +26,8 @@ if (isset($_GET['updated']) && $_GET['updated'] === 'true') {
-

-

+

+

@@ -36,108 +40,100 @@ if (isset($_GET['updated']) && $_GET['updated'] === 'true') { type="checkbox" name="widgets[]" value="1" - enabled_widgets[$widget_id])); ?> + />

- get_widget_description($widget_id); ?> + get_widget_description($widget_id); ?>

+

+

+ + get_available_system_widgets(); + $disabled_widgets = get_site_option('msd_disabled_system_widgets', []); + + if (!empty($available_widgets)): + ?> +
+ + + +
+

+ $widget_data): ?> +
+ +
+ +
+ + + +
+

+ $widget_data): ?> +
+ +
+ +
+ +
+

+
+

+

+ + + +
+
+ +
+ +
+

+
+ +

-
-

-

- -
- 'WordPress News', - 'url' => 'https://wordpress.org/news/feed/', - 'enabled' => true - ] - ]); - ?> - -
-

- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - -
- -
-

-
- -
- -
- - - -
- -
-

-
-
- WordPress News: - https://wordpress.org/news/feed/ -
-
- WP Tavern: - https://wptavern.com/feed -
-
-

- -

-
-
-
-

@@ -151,217 +147,317 @@ if (isset($_GET['updated']) && $_GET['updated'] === 'true') { +

- +

+ +
+

+

+ +
+
+ + +
+ +
+ + + + +
+
+
diff --git a/wp-multisite-dashboard.php b/wp-multisite-dashboard.php index 73082b1..919e080 100644 --- a/wp-multisite-dashboard.php +++ b/wp-multisite-dashboard.php @@ -19,1288 +19,56 @@ 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__)); -class WP_Multisite_Dashboard { +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'; - private static $instance = null; - private $enabled_widgets = []; - - public static function get_instance() { - if (self::$instance === null) { - self::$instance = new self(); - } - return self::$instance; +function wp_msd_init() { + if (!is_multisite()) { + add_action('admin_notices', 'wp_msd_multisite_required_notice'); + return; } - private function __construct() { - add_action('init', [$this, 'init']); - add_action('admin_init', [$this, 'admin_init']); - add_action('network_admin_menu', [$this, 'add_admin_menu']); - - $this->register_ajax_actions(); - } - - private function register_ajax_actions() { - $ajax_actions = [ - 'msd_get_network_overview', - 'msd_get_site_list', - 'msd_get_storage_data', - 'msd_get_server_info', - 'msd_get_version_info', - 'msd_get_custom_news', - 'msd_get_network_settings', - 'msd_get_user_management', - 'msd_get_last_edits', - 'msd_get_todo_items', - 'msd_save_news_sources', - 'msd_save_quick_links', - 'msd_save_contact_info', - 'msd_save_todo_item', - 'msd_update_todo_item', - 'msd_delete_todo_item', - 'msd_toggle_todo_complete', - 'msd_reorder_quick_links', - 'msd_toggle_widget', - 'msd_refresh_widget_data', - 'msd_clear_cache', - 'msd_manage_user_action' - ]; - - foreach ($ajax_actions as $action) { - add_action("wp_ajax_{$action}", [$this, str_replace('msd_', '', $action)]); - } - } - - public function init() { - if (!is_multisite()) { - add_action('admin_notices', [$this, 'multisite_required_notice']); - return; - } - - load_plugin_textdomain('wp-multisite-dashboard'); - - $this->enabled_widgets = get_site_option('msd_enabled_widgets', [ - 'msd_network_overview' => 1, - 'msd_quick_site_management' => 1, - 'msd_storage_performance' => 1, - 'msd_server_info' => 1, - 'msd_quick_links' => 1, - 'msd_version_info' => 1, - 'msd_custom_news' => 1, - 'msd_network_settings' => 1, - 'msd_user_management' => 1, - 'msd_contact_info' => 1, - 'msd_last_edits' => 1, - 'msd_todo_widget' => 1 - ]); - - $this->load_dependencies(); - $this->enhance_network_dashboard(); - } - - private function load_dependencies() { - require_once WP_MSD_PLUGIN_DIR . 'includes/class-network-data.php'; - require_once WP_MSD_PLUGIN_DIR . 'includes/class-user-manager.php'; - } - - private function enhance_network_dashboard() { - add_filter('dashboard_recent_posts_query_args', [$this, 'enhance_recent_posts']); - add_action('wp_network_dashboard_setup', [$this, 'enhance_right_now_widget']); - add_action('admin_footer', [$this, 'add_right_now_enhancements']); - } - - public function enhance_recent_posts($query_args) { - $query_args['post_status'] = 'publish'; - return $query_args; - } - - public function enhance_right_now_widget() { - add_action('network_dashboard_right_now_content_table_end', [$this, 'add_right_now_plugin_link']); - } - - public function add_right_now_plugin_link() { - if (!current_user_can('manage_network_plugins')) { - return; - } - - echo ''; - echo '' . __('Add New Plugin', 'wp-multisite-dashboard') . ''; - echo '' . __('Manage Plugins', 'wp-multisite-dashboard') . ''; - echo ''; - } - - public function add_right_now_enhancements() { - $screen = get_current_screen(); - if (!$screen || $screen->id !== 'dashboard-network') { - return; - } - - $sites_count = get_sites(['count' => true]); - $users_count = count_users()['total_users']; - $themes_count = count(wp_get_themes(['allowed' => 'network'])); - $plugins_count = count(get_plugins()); - ?> - - - - ['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'] - ]; - - foreach ($widgets as $widget_id => $widget_data) { - if (!empty($this->enabled_widgets[$widget_id])) { - wp_add_dashboard_widget( - $widget_id, - $widget_data[0], - [$this, $widget_data[1]] - ); - } - } - } - - public function enqueue_admin_scripts($hook) { - $allowed_hooks = ['index.php', 'dashboard.php', 'settings_page_msd-settings']; - - if (!in_array($hook, $allowed_hooks)) { - return; - } - - wp_enqueue_script( - 'msd-dashboard', - WP_MSD_PLUGIN_URL . 'assets/dashboard.js', - ['jquery', 'jquery-ui-sortable'], - WP_MSD_VERSION, - true - ); - - wp_enqueue_style( - 'msd-dashboard', - WP_MSD_PLUGIN_URL . 'assets/dashboard.css', - [], - WP_MSD_VERSION - ); - - wp_localize_script('msd-dashboard', 'msdAjax', [ - 'ajaxurl' => admin_url('admin-ajax.php'), - 'nonce' => wp_create_nonce('msd_ajax_nonce'), - 'strings' => [ - 'confirm_action' => __('Are you sure?', 'wp-multisite-dashboard'), - 'loading' => __('Loading...', 'wp-multisite-dashboard'), - 'error_occurred' => __('An error occurred', 'wp-multisite-dashboard'), - 'refresh_success' => __('Data refreshed successfully', 'wp-multisite-dashboard'), - 'confirm_delete' => __('Are you sure you want to delete this item?', 'wp-multisite-dashboard'), - 'save_success' => __('Saved successfully', 'wp-multisite-dashboard') - ] - ]); - } - - 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' - ]; - - include WP_MSD_PLUGIN_DIR . 'templates/settings-page.php'; - } - - 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' - ]; - - foreach ($widget_options as $widget_id) { - if (isset($_POST['widgets'][$widget_id])) { - $enabled_widgets[$widget_id] = 1; - } - } - - update_site_option('msd_enabled_widgets', $enabled_widgets); - $this->enabled_widgets = $enabled_widgets; - - wp_safe_redirect(add_query_arg('updated', 'true', network_admin_url('settings.php?page=msd-settings'))); - exit; - } - - private 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') - ]; - - return $descriptions[$widget_id] ?? ''; - } - - public function render_network_overview_widget() { - echo '
'; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function render_quick_site_widget() { - echo '
'; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function render_storage_performance_widget() { - echo '
'; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function render_contact_info_widget() { - echo '
'; - echo ''; - $this->render_contact_info_content(); - echo '
'; - $this->render_contact_info_modal(); - } - - 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' => '' - ]); - - echo '
'; - echo '
'; - echo '

' . esc_html($contact_info['name']) . '

'; - echo '
'; - - echo '
'; - - if (!empty($contact_info['description'])) { - echo '

' . esc_html($contact_info['description']) . '

'; - } - - echo '
'; - echo ''; - echo '' . esc_html($contact_info['email']) . ''; - echo '
'; - - if (!empty($contact_info['phone'])) { - echo '
'; - echo ''; - echo '' . esc_html($contact_info['phone']) . ''; - echo '
'; - } - - echo '
'; - echo ''; - echo '' . esc_html($contact_info['website']) . ''; - echo '
'; - - $im_fields = [ - 'qq' => ['QQ', 'dashicons-admin-users'], - 'wechat' => ['WeChat', 'dashicons-format-chat'], - 'whatsapp' => ['WhatsApp', 'dashicons-smartphone'], - 'telegram' => ['Telegram', 'dashicons-email-alt'] - ]; - - foreach ($im_fields as $field => $data) { - if (!empty($contact_info[$field])) { - echo '
'; - echo ''; - echo '' . $data[0] . ': ' . esc_html($contact_info[$field]) . ''; - echo '
'; - } - } - - if (!empty($contact_info['qr_code'])) { - echo '
'; - echo 'QR Code'; - echo '
'; - } - - echo '
'; - - echo '
'; - echo ''; - echo '
'; - - echo '
'; - } - - private function render_contact_info_modal() { - include WP_MSD_PLUGIN_DIR . 'templates/contact-info-modal.php'; - } - - public function render_last_edits_widget() { - echo '
'; - echo ''; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function render_network_settings_widget() { - echo '
'; - echo ''; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function render_user_management_widget() { - echo '
'; - echo ''; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function render_server_info_widget() { - echo '
'; - echo ''; - $this->render_server_info_content(); - echo '
'; - } - - 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()), - ]; - - $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', - ]; - - echo '
'; - foreach ($data as $label => $value) { - $icon = $icons[$label] ?? 'dashicons-info'; - echo '
'; - echo ''; - echo '' . esc_html($label) . ''; - echo '' . esc_html($value) . ''; - echo '
'; - } - echo '
'; - } - - public function render_version_info_widget() { - echo '
'; - echo ''; - $this->render_version_info_content(); - echo '
'; - } - - private function render_version_info_content() { - $plugin_data = get_plugin_data(__FILE__); - global $wpdb; - - echo '
'; - echo '

' . esc_html($plugin_data['Name']) . '

'; - echo '
'; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '
'; - echo '
'; - - echo '
'; - - echo '
'; - echo ''; - echo 'Plugin Version'; - echo '' . esc_html($plugin_data['Version']) . ''; - echo '
'; - - echo '
'; - echo ''; - echo 'Author URI'; - echo '' . esc_html($plugin_data['AuthorURI']) . ''; - echo '
'; - - echo '
'; - echo ''; - echo 'Required PHP'; - echo '' . esc_html($plugin_data['RequiresPHP']) . ''; - echo '
'; - - echo '
'; - echo ''; - echo 'Database Tables'; - $activity_table = $wpdb->base_prefix . 'msd_activity_log'; - $activity_exists = $wpdb->get_var("SHOW TABLES LIKE '{$activity_table}'") === $activity_table; - if ($activity_exists) { - echo '✓ Activity table created'; - } else { - echo '⚠ Activity table missing'; - } - echo '
'; - - echo '
'; - - echo '
'; - echo '

' . esc_html(strip_tags($plugin_data['Description'])) . '

'; - echo '
'; - } - - public function render_custom_news_widget() { - echo '
'; - echo ''; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - $this->render_news_sources_modal(); - } - - private function render_news_sources_modal() { - include WP_MSD_PLUGIN_DIR . 'templates/news-sources-modal.php'; - } - - public function render_quick_links_widget() { - $quick_links = get_site_option('msd_quick_links', []); - - echo ''; - $this->render_quick_links_modal(); - } - - private function render_quick_links_modal() { - include WP_MSD_PLUGIN_DIR . 'templates/quick-links-modal.php'; - } - - public function render_todo_widget() { - echo '
'; - echo ''; - echo '
' . __('Loading...', 'wp-multisite-dashboard') . '
'; - echo '
'; - } - - public function get_network_overview() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $network_data = new WP_MSD_Network_Data(); - $overview = [ - 'total_posts' => $network_data->get_total_posts(), - 'total_pages' => $network_data->get_total_pages(), - 'multisite_config' => $network_data->get_multisite_configuration(), - 'network_info' => $network_data->get_network_information(), - 'critical_alerts' => 0, - 'network_status' => $network_data->get_overall_network_status(), - 'last_updated' => current_time('mysql') - ]; - - wp_send_json_success($overview); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load network overview', 'wp-multisite-dashboard')); - } - } - - public function get_site_list() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $network_data = new WP_MSD_Network_Data(); - $sites = $network_data->get_recent_active_sites(10); - wp_send_json_success($sites); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load sites', 'wp-multisite-dashboard')); - } - } - - public function get_storage_data() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $network_data = new WP_MSD_Network_Data(); - $storage_data = $network_data->get_storage_usage_data(5); - wp_send_json_success($storage_data); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load storage data', 'wp-multisite-dashboard')); - } - } - - public function get_last_edits() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $network_data = new WP_MSD_Network_Data(); - $last_edits = $network_data->get_recent_network_activity(10); - wp_send_json_success($last_edits); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load recent activity', 'wp-multisite-dashboard')); - } - } - - public function get_todo_items() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $todos = get_user_meta(get_current_user_id(), 'msd_todos', true); - if (!is_array($todos)) { - $todos = []; - } - - // Format todos with human readable dates - foreach ($todos as &$todo) { - if (isset($todo['created_at'])) { - $todo['created_at_human'] = human_time_diff(strtotime($todo['created_at'])) . ' ago'; - } - if (isset($todo['updated_at'])) { - $todo['updated_at_human'] = human_time_diff(strtotime($todo['updated_at'])) . ' ago'; - } - } - - wp_send_json_success($todos); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load todo items', 'wp-multisite-dashboard')); - } - } - - public function save_contact_info() { - if (!$this->verify_ajax_request()) { - return; - } - - $contact_info = [ - 'name' => sanitize_text_field($_POST['name'] ?? ''), - 'email' => sanitize_email($_POST['email'] ?? ''), - 'phone' => sanitize_text_field($_POST['phone'] ?? ''), - 'website' => esc_url_raw($_POST['website'] ?? ''), - 'description' => sanitize_textarea_field($_POST['description'] ?? ''), - 'qq' => sanitize_text_field($_POST['qq'] ?? ''), - 'wechat' => sanitize_text_field($_POST['wechat'] ?? ''), - 'whatsapp' => sanitize_text_field($_POST['whatsapp'] ?? ''), - 'telegram' => sanitize_text_field($_POST['telegram'] ?? ''), - 'qr_code' => esc_url_raw($_POST['qr_code'] ?? '') - ]; - - update_site_option('msd_contact_info', $contact_info); - wp_send_json_success(['message' => __('Contact information saved successfully', 'wp-multisite-dashboard')]); - } - - public function save_todo_item() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $title = sanitize_text_field($_POST['title'] ?? ''); - $description = sanitize_textarea_field($_POST['description'] ?? ''); - - if (empty($title)) { - wp_send_json_error(__('Title is required', 'wp-multisite-dashboard')); - return; - } - - $todos = get_user_meta(get_current_user_id(), 'msd_todos', true); - if (!is_array($todos)) { - $todos = []; - } - - $new_todo = [ - 'id' => uniqid(), - 'title' => $title, - 'description' => $description, - 'completed' => false, - 'priority' => sanitize_text_field($_POST['priority'] ?? 'medium'), - 'created_at' => current_time('mysql'), - 'updated_at' => current_time('mysql') - ]; - - $todos[] = $new_todo; - - $result = update_user_meta(get_current_user_id(), 'msd_todos', $todos); - - if ($result) { - wp_send_json_success(['message' => __('Todo item created', 'wp-multisite-dashboard')]); - } else { - wp_send_json_error(__('Failed to create todo item', 'wp-multisite-dashboard')); - } - } catch (Exception $e) { - wp_send_json_error(__('Failed to create todo item', 'wp-multisite-dashboard')); - } - } - - public function update_todo_item() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $id = sanitize_text_field($_POST['id'] ?? ''); - $title = sanitize_text_field($_POST['title'] ?? ''); - $description = sanitize_textarea_field($_POST['description'] ?? ''); - - if (empty($id) || empty($title)) { - wp_send_json_error(__('ID and title are required', 'wp-multisite-dashboard')); - return; - } - - $todos = get_user_meta(get_current_user_id(), 'msd_todos', true); - if (!is_array($todos)) { - wp_send_json_error(__('No todos found', 'wp-multisite-dashboard')); - return; - } - - $updated = false; - foreach ($todos as &$todo) { - if ($todo['id'] === $id) { - $todo['title'] = $title; - $todo['description'] = $description; - if (isset($_POST['priority'])) { - $todo['priority'] = sanitize_text_field($_POST['priority']); - } - $todo['updated_at'] = current_time('mysql'); - $updated = true; - break; - } - } - - if ($updated) { - $result = update_user_meta(get_current_user_id(), 'msd_todos', $todos); - if ($result) { - wp_send_json_success(['message' => __('Todo item updated', 'wp-multisite-dashboard')]); - } else { - wp_send_json_error(__('Failed to update todo item', 'wp-multisite-dashboard')); - } - } else { - wp_send_json_error(__('Todo item not found', 'wp-multisite-dashboard')); - } - } catch (Exception $e) { - wp_send_json_error(__('Failed to update todo item', 'wp-multisite-dashboard')); - } - } - - public function delete_todo_item() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $id = sanitize_text_field($_POST['id'] ?? ''); - - if (empty($id)) { - wp_send_json_error(__('ID is required', 'wp-multisite-dashboard')); - return; - } - - $todos = get_user_meta(get_current_user_id(), 'msd_todos', true); - if (!is_array($todos)) { - wp_send_json_error(__('No todos found', 'wp-multisite-dashboard')); - return; - } - - $filtered_todos = array_filter($todos, function($todo) use ($id) { - return $todo['id'] !== $id; - }); - - if (count($filtered_todos) < count($todos)) { - $result = update_user_meta(get_current_user_id(), 'msd_todos', array_values($filtered_todos)); - if ($result) { - wp_send_json_success(['message' => __('Todo item deleted', 'wp-multisite-dashboard')]); - } else { - wp_send_json_error(__('Failed to delete todo item', 'wp-multisite-dashboard')); - } - } else { - wp_send_json_error(__('Todo item not found', 'wp-multisite-dashboard')); - } - } catch (Exception $e) { - wp_send_json_error(__('Failed to delete todo item', 'wp-multisite-dashboard')); - } - } - - public function toggle_todo_complete() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $id = sanitize_text_field($_POST['id'] ?? ''); - - if (empty($id)) { - wp_send_json_error(__('ID is required', 'wp-multisite-dashboard')); - return; - } - - $todos = get_user_meta(get_current_user_id(), 'msd_todos', true); - if (!is_array($todos)) { - wp_send_json_error(__('No todos found', 'wp-multisite-dashboard')); - return; - } - - $updated = false; - foreach ($todos as &$todo) { - if ($todo['id'] === $id) { - $todo['completed'] = !$todo['completed']; - $todo['updated_at'] = current_time('mysql'); - $updated = true; - break; - } - } - - if ($updated) { - $result = update_user_meta(get_current_user_id(), 'msd_todos', $todos); - if ($result) { - wp_send_json_success(['message' => __('Todo status updated', 'wp-multisite-dashboard')]); - } else { - wp_send_json_error(__('Failed to update todo status', 'wp-multisite-dashboard')); - } - } else { - wp_send_json_error(__('Todo item not found', 'wp-multisite-dashboard')); - } - } catch (Exception $e) { - wp_send_json_error(__('Failed to update todo status', 'wp-multisite-dashboard')); - } - } - - public function reorder_quick_links() { - if (!$this->verify_ajax_request()) { - return; - } - - $order = $_POST['order'] ?? []; - if (!is_array($order)) { - wp_send_json_error(__('Invalid order data', 'wp-multisite-dashboard')); - return; - } - - $current_links = get_site_option('msd_quick_links', []); - $reordered_links = []; - - foreach ($order as $index) { - $index = intval($index); - if (isset($current_links[$index])) { - $reordered_links[] = $current_links[$index]; - } - } - - update_site_option('msd_quick_links', $reordered_links); - wp_send_json_success(['message' => __('Links reordered successfully', 'wp-multisite-dashboard')]); - } - - public function get_user_management() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $user_manager = new WP_MSD_User_Manager(); - $user_data = $user_manager->get_recent_users_data(); - wp_send_json_success($user_data); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load user data', 'wp-multisite-dashboard')); - } - } - - public function manage_user_action() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $action = sanitize_text_field($_POST['user_action'] ?? ''); - $user_id = intval($_POST['user_id'] ?? 0); - $additional_data = $_POST['additional_data'] ?? []; - - $user_manager = new WP_MSD_User_Manager(); - $result = $user_manager->perform_single_user_action($action, $user_id, $additional_data); - - if ($result['success']) { - wp_send_json_success($result); - } else { - wp_send_json_error($result['message']); - } - } catch (Exception $e) { - wp_send_json_error(__('Failed to perform user action', 'wp-multisite-dashboard')); - } - } - - public function get_server_info() { - if (!$this->verify_ajax_request()) { - return; - } - - global $wpdb, $wp_version; - - $server_info = [ - 'wordpress_version' => $wp_version, - 'php_version' => phpversion(), - 'mysql_version' => $wpdb->db_version(), - 'server_software' => $_SERVER["SERVER_SOFTWARE"] ?? 'Unknown', - 'server_time' => current_time('Y-m-d H:i:s'), - 'php_memory_limit' => ini_get('memory_limit'), - 'max_upload_size' => size_format(wp_max_upload_size()), - 'active_plugins' => count(get_option('active_plugins', [])), - 'total_users' => count_users()['total_users'], - 'last_updated' => current_time('mysql') - ]; - - wp_send_json_success($server_info); - } - - public function get_version_info() { - if (!$this->verify_ajax_request()) { - return; - } - - $plugin_data = get_plugin_data(__FILE__); - global $wpdb; - - $activity_table = $wpdb->base_prefix . 'msd_activity_log'; - $activity_exists = $wpdb->get_var("SHOW TABLES LIKE '{$activity_table}'") === $activity_table; - - $version_info = [ - 'plugin_name' => $plugin_data['Name'], - 'plugin_version' => $plugin_data['Version'], - 'plugin_author' => $plugin_data['Author'], - 'plugin_uri' => $plugin_data['AuthorURI'], - 'text_domain' => $plugin_data['TextDomain'], - 'required_php' => $plugin_data['RequiresPHP'], - 'network_sites' => get_sites(['count' => true]), - 'description' => strip_tags($plugin_data['Description']), - 'database_status' => $activity_exists ? 'active' : 'missing', - 'database_message' => $activity_exists ? 'Activity table created' : 'Activity table missing', - 'last_updated' => current_time('mysql') - ]; - - wp_send_json_success($version_info); - } - - public function get_custom_news() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $news_sources = get_site_option('msd_news_sources', []); - $news_items = []; - - foreach ($news_sources as $source) { - if (!$source['enabled']) continue; - - $feed_items = $this->fetch_rss_feed($source['url'], 5); - foreach ($feed_items as $item) { - $item['source'] = $source['name']; - $news_items[] = $item; - } - } - - usort($news_items, function($a, $b) { - return strtotime($b['date']) - strtotime($a['date']); - }); - - $news_items = array_slice($news_items, 0, 10); - - wp_send_json_success($news_items); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load news', 'wp-multisite-dashboard')); - } - } - - private function fetch_rss_feed($url, $limit = 5) { - $cache_key = 'msd_rss_' . md5($url); - $cached = get_site_transient($cache_key); - - if ($cached !== false) { - return $cached; - } - - $response = wp_remote_get($url, [ - 'timeout' => 15, - 'headers' => [ - 'User-Agent' => 'WP-Multisite-Dashboard/' . WP_MSD_VERSION - ] - ]); - - if (is_wp_error($response)) { - return []; - } - - $body = wp_remote_retrieve_body($response); - $feed_items = []; - - try { - $xml = simplexml_load_string($body); - if ($xml === false) { - return []; - } - - $items = $xml->channel->item ?? $xml->entry ?? []; - $count = 0; - - foreach ($items as $item) { - if ($count >= $limit) break; - - $title = (string)($item->title ?? ''); - $link = (string)($item->link ?? $item->link['href'] ?? ''); - $description = (string)($item->description ?? $item->summary ?? ''); - $date = (string)($item->pubDate ?? $item->updated ?? ''); - - if (!empty($title) && !empty($link)) { - $description = html_entity_decode($description, ENT_QUOTES, 'UTF-8'); - $description = wp_trim_words(strip_tags($description), 20); - - $feed_items[] = [ - 'title' => html_entity_decode($title, ENT_QUOTES, 'UTF-8'), - 'link' => $link, - 'description' => $description, - 'date' => $date - ]; - $count++; - } - } - } catch (Exception $e) { - return []; - } - - set_site_transient($cache_key, $feed_items, 3600); - return $feed_items; - } - - public function save_news_sources() { - if (!$this->verify_ajax_request()) { - return; - } - - $sources = []; - if (isset($_POST['sources']) && is_array($_POST['sources'])) { - foreach ($_POST['sources'] as $source) { - if (!empty($source['name']) && !empty($source['url'])) { - $sources[] = [ - 'name' => sanitize_text_field($source['name']), - 'url' => esc_url_raw($source['url']), - 'enabled' => !empty($source['enabled']) - ]; - } - } - } - - update_site_option('msd_news_sources', $sources); - - $cache_keys = []; - foreach ($sources as $source) { - $cache_keys[] = 'msd_rss_' . md5($source['url']); - } - - foreach ($cache_keys as $key) { - delete_site_transient($key); - } - - wp_send_json_success(['message' => __('News sources saved successfully', 'wp-multisite-dashboard')]); - } - - public function save_quick_links() { - if (!$this->verify_ajax_request()) { - return; - } - - $links = []; - if (isset($_POST['links']) && is_array($_POST['links'])) { - foreach ($_POST['links'] as $link) { - if (!empty($link['title']) && !empty($link['url'])) { - $links[] = [ - 'title' => sanitize_text_field($link['title']), - 'url' => esc_url_raw($link['url']), - 'icon' => sanitize_text_field($link['icon']), - 'new_tab' => !empty($link['new_tab']) - ]; - } - } - } - - update_site_option('msd_quick_links', $links); - wp_send_json_success(['message' => __('Quick links saved successfully', 'wp-multisite-dashboard')]); - } - - public function toggle_widget() { - if (!$this->verify_ajax_request()) { - return; - } - - $widget_id = sanitize_text_field($_POST['widget_id'] ?? ''); - $enabled = !empty($_POST['enabled']); - - if (empty($widget_id)) { - wp_send_json_error(__('Invalid widget ID', 'wp-multisite-dashboard')); - } - - $this->enabled_widgets[$widget_id] = $enabled ? 1 : 0; - update_site_option('msd_enabled_widgets', $this->enabled_widgets); - - wp_send_json_success(['message' => __('Widget settings updated', 'wp-multisite-dashboard')]); - } - - public function refresh_widget_data() { - if (!$this->verify_ajax_request()) { - return; - } - - $widget = sanitize_text_field($_POST['widget'] ?? ''); - - if (class_exists('WP_MSD_Network_Data')) { - $network_data = new WP_MSD_Network_Data(); - $network_data->clear_widget_cache($widget); - } - - wp_send_json_success(['message' => __('Cache cleared', 'wp-multisite-dashboard')]); - } - - public function clear_cache() { - if (!wp_verify_nonce($_POST['nonce'] ?? '', 'msd_clear_cache')) { - wp_send_json_error(__('Invalid nonce', 'wp-multisite-dashboard')); - return; - } - - if (!current_user_can('manage_network')) { - wp_send_json_error(__('Insufficient permissions', 'wp-multisite-dashboard')); - return; - } - - $cache_type = sanitize_text_field($_POST['cache_type'] ?? 'all'); - - try { - switch ($cache_type) { - case 'network': - if (class_exists('WP_MSD_Network_Data')) { - $network_data = new WP_MSD_Network_Data(); - $network_data->clear_all_caches(); - } - break; - - case 'all': - default: - if (class_exists('WP_MSD_Network_Data')) { - $network_data = new WP_MSD_Network_Data(); - $network_data->clear_all_caches(); - } - wp_cache_flush(); - break; - } - - wp_send_json_success(['message' => __('Cache cleared successfully', 'wp-multisite-dashboard')]); - } catch (Exception $e) { - wp_send_json_error(__('Failed to clear cache', 'wp-multisite-dashboard')); - } - } - - public function get_network_settings() { - if (!$this->verify_ajax_request()) { - return; - } - - try { - $network_data = new WP_MSD_Network_Data(); - $settings_data = $network_data->get_network_settings_overview(); - wp_send_json_success($settings_data); - } catch (Exception $e) { - wp_send_json_error(__('Failed to load network settings', 'wp-multisite-dashboard')); - } - } - - private function verify_ajax_request() { - if (!wp_verify_nonce($_POST['nonce'] ?? '', 'msd_ajax_nonce')) { - wp_send_json_error(__('Invalid nonce', 'wp-multisite-dashboard')); - return false; - } - - if (!current_user_can('manage_network')) { - wp_send_json_error(__('Insufficient permissions', 'wp-multisite-dashboard')); - return false; - } - - return true; - } - - public function multisite_required_notice() { - echo '

'; - echo __('WP Multisite Dashboard requires WordPress Multisite to be enabled.', 'wp-multisite-dashboard'); - echo '

'; - } + WP_MSD_Plugin_Core::get_instance(); } -register_activation_hook(__FILE__, function() { +function wp_msd_multisite_load_textdomain() { + load_plugin_textdomain('wp-multisite-dashboard', false, dirname(plugin_basename(__FILE__)) . '/languages'); +} +add_action('plugins_loaded', 'wp_msd_multisite_load_textdomain'); + + +function wp_msd_multisite_required_notice() { + echo '

'; + echo __('WP Multisite Dashboard requires WordPress Multisite to be enabled.', 'wp-multisite-dashboard'); + echo '

'; +} + +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')); } - require_once WP_MSD_PLUGIN_DIR . 'includes/class-network-data.php'; - $network_data = new WP_MSD_Network_Data(); $network_data->create_activity_log_table(); set_site_transient('msd_activation_notice', true, 30); -}); +} -add_action('network_admin_notices', function() { +add_action('network_admin_notices', 'wp_msd_activation_notice'); +function wp_msd_activation_notice() { if (get_site_transient('msd_activation_notice')) { echo '
'; echo '

' . __('WP Multisite Dashboard has been activated successfully!', 'wp-multisite-dashboard') . '

'; echo '
'; delete_site_transient('msd_activation_notice'); } -}); +} -WP_Multisite_Dashboard::get_instance(); - -require_once plugin_dir_path(__FILE__) . 'lib/plugin-update-checker/plugin-update-checker.php'; -use YahnisElsts\PluginUpdateChecker\v5p3\PucFactory; - -$WPMultisiteDashboardUpdateChecker = PucFactory::buildUpdateChecker( - 'https://updates.weixiaoduo.com/wp-multisite-dashboard.json', - __FILE__, - 'wp-multisite-dashboard' -); +add_action('plugins_loaded', 'wp_msd_init');