From 48622cdbd87addbe8e2863115ad317a786ce0dcb Mon Sep 17 00:00:00 2001 From: feng Date: Mon, 16 Jun 2025 01:03:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E7=89=88=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- languages/wp-multinetwork-adminbar-zh_CN.mo | Bin 0 -> 1444 bytes languages/wp-multinetwork-adminbar-zh_CN.po | 80 ++++ languages/wp-multinetwork-adminbar.pot | 80 ++++ readme.txt | 187 ++++++++ wp-multinetwork-adminbar.php | 498 ++++++++++++++++++++ 5 files changed, 845 insertions(+) create mode 100644 languages/wp-multinetwork-adminbar-zh_CN.mo create mode 100644 languages/wp-multinetwork-adminbar-zh_CN.po create mode 100644 languages/wp-multinetwork-adminbar.pot create mode 100644 readme.txt create mode 100644 wp-multinetwork-adminbar.php diff --git a/languages/wp-multinetwork-adminbar-zh_CN.mo b/languages/wp-multinetwork-adminbar-zh_CN.mo new file mode 100644 index 0000000000000000000000000000000000000000..7854ce6169b7f8b5f84f7e8eff5dfe5b5591e8dd GIT binary patch literal 1444 zcmaiy&u<$=6vqcJzf6Hr#4mxwAQY(;+RY{?A=)&EG^8j}UEE?QH#G51?4j!!Gc#L< zoV=VJKl5hhz4v{y z@9zVtZxD{{r`c z{p|e+S-@9;ZvamKUjbHuF9KJ9CjRfhi{SGY(DhV8^D)g z|Ifs}12p~*Jcy73+z;#rjsl+nYM_ZT2Yd*46$oj&YXExGd|;Ruk9SuPE8)YyN0N0q zA*AaL2!o!0X|zHK=rNex(c@voG(`y&8VjVPT;tyg~9{2gN4LJRsaeAdpi^O znwf{dTHr~FDJPRY^=w4E5-6D@G8HF>LtUYiV;;YcLcSm#NJ<@xxqDzVCYP|%M5~mE zuTWNsk7-_86Q1<}mF68?d@75(3U(e5k9N}@Arkl5j_ssR(z1}+%BTYKtRq1|Svle2 zqSj^Q_V!lFC8IydX6HqzR|RF`k-81^8sI\n" +"Language-Team: Chinese (China)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 3.6\n" + +#: wp-multinetwork-adminbar.php:96 +#, php-format +msgid "Current Network: %s" +msgstr "当前网络:%s" + +#: wp-multinetwork-adminbar.php:123 +msgid "Manage All Networks" +msgstr "管理所有网络" + +#: wp-multinetwork-adminbar.php:133 +#, php-format +msgid "Network: %s%s (%d sites)" +msgstr "网络:%s%s(%d 个站点)" + +#: wp-multinetwork-adminbar.php:195 +#, php-format +msgid "%d site" +msgid_plural "%d sites" +msgstr[0] "%d 个站点" + +#: wp-multinetwork-adminbar.php:228 +msgid "Insufficient permissions." +msgstr "权限不足。" + +#: wp-multinetwork-adminbar.php:236 +msgid "Network does not exist." +msgstr "网络不存在。" + +#: wp-multinetwork-adminbar.php:267 +msgid "Switching..." +msgstr "切换中..." + +#: wp-multinetwork-adminbar.php:281 +msgid "Network Switcher" +msgstr "网络切换器" + +#: wp-multinetwork-adminbar.php:293 +msgid "This plugin requires WordPress Multisite to be enabled." +msgstr "此插件需要启用 WordPress 多站点功能。" + +#: wp-multinetwork-adminbar.php:294 +msgid "Plugin Activation Error" +msgstr "插件激活错误" + +#: wp-multinetwork-adminbar.php:303 +msgid "This plugin requires WordPress 5.0 or higher." +msgstr "此插件需要 WordPress 5.0 或更高版本。" + +# Context: Admin bar tooltip +msgctxt "admin bar" +msgid "Switch between networks" +msgstr "在网络之间切换" + +# Context: Network statistics +msgctxt "network stats" +msgid "sites" +msgstr "站点" + +# Context: Loading state +msgctxt "loading" +msgid "Loading networks..." +msgstr "加载网络中..." diff --git a/languages/wp-multinetwork-adminbar.pot b/languages/wp-multinetwork-adminbar.pot new file mode 100644 index 0000000..4a17784 --- /dev/null +++ b/languages/wp-multinetwork-adminbar.pot @@ -0,0 +1,80 @@ +# WP Multi Network Admin Bar Translation Template +# Copyright (C) 2025 WPMultiNetwork.com +# This file is distributed under the same license as the WP Multi Network Admin Bar plugin. +msgid "" +msgstr "" +"Project-Id-Version: WP Multi Network Admin Bar 1.0.0\n" +"Report-Msgid-Bugs-To: https://wpmultinetwork.com/support\n" +"POT-Creation-Date: 2025-06-15 12:00+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: wp-multinetwork-adminbar.php:96 +#, php-format +msgid "Current Network: %s" +msgstr "" + +#: wp-multinetwork-adminbar.php:123 +msgid "Manage All Networks" +msgstr "" + +#: wp-multinetwork-adminbar.php:133 +#, php-format +msgid "Network: %s%s (%d sites)" +msgstr "" + +#: wp-multinetwork-adminbar.php:195 +#, php-format +msgid "%d site" +msgid_plural "%d sites" +msgstr[0] "" +msgstr[1] "" + +#: wp-multinetwork-adminbar.php:228 +msgid "Insufficient permissions." +msgstr "" + +#: wp-multinetwork-adminbar.php:236 +msgid "Network does not exist." +msgstr "" + +#: wp-multinetwork-adminbar.php:267 +msgid "Switching..." +msgstr "" + +#: wp-multinetwork-adminbar.php:281 +msgid "Network Switcher" +msgstr "" + +#: wp-multinetwork-adminbar.php:293 +msgid "This plugin requires WordPress Multisite to be enabled." +msgstr "" + +#: wp-multinetwork-adminbar.php:294 +msgid "Plugin Activation Error" +msgstr "" + +#: wp-multinetwork-adminbar.php:303 +msgid "This plugin requires WordPress 5.0 or higher." +msgstr "" + +# Context: Admin bar tooltip +msgctxt "admin bar" +msgid "Switch between networks" +msgstr "" + +# Context: Network statistics +msgctxt "network stats" +msgid "sites" +msgstr "" + +# Context: Loading state +msgctxt "loading" +msgid "Loading networks..." +msgstr "" \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..85b8fe7 --- /dev/null +++ b/readme.txt @@ -0,0 +1,187 @@ +=== WP Multi Network Admin Bar === +Contributors: wpmultinetwork +Tags: multisite, multi-network, admin bar, network switching, network management +Requires at least: 5.0 +Tested up to: 6.8 +Requires PHP: 7.4 +Stable tag: 1.0.0 +License: GPLv2 or later +License URI: https://www.gnu.org/licenses/gpl-2.0.html +Network: true + +Display current network information in admin bar and provide seamless network switching functionality for WP Multi Network environments. + +== Description == + +**WP Multi Network Admin Bar** enhances the WordPress admin experience for Multi Network environments by adding intelligent network identification and switching capabilities directly to the admin bar. + += Key Features = + +* **Network Identification** - Clearly displays the current network name and site count in the admin bar +* **Quick Network Switching** - One-click switching between different networks with dropdown menu +* **Network Statistics** - Shows the number of sites in each network for better overview +* **Smart Navigation** - Maintains admin context when switching between networks +* **Performance Optimized** - Uses caching to avoid database overhead +* **Fully Translatable** - Complete internationalization support with translation files +* **WordPress 6.8 Compatible** - Tested with the latest WordPress version +* **Mobile Responsive** - Works seamlessly on all device sizes +* **Accessibility Ready** - Full ARIA support and keyboard navigation + += Perfect For = + +* **SaaS Platform Developers** - Managing multiple client networks +* **Enterprise Administrators** - Overseeing multi-brand websites +* **Agency Owners** - Handling multiple client sites efficiently +* **Educational Institutions** - Managing multi-campus networks +* **Media Companies** - Operating regional or topical site networks + += How It Works = + +Once activated, the plugin automatically detects your Multi Network setup and adds a network indicator to the admin bar. The indicator shows: + +1. **Current Network Icon** (🌐) for easy visual identification +2. **Network Name** - The display name of your current network +3. **Site Count** - Number of sites in parentheses (e.g., "Main Network (15)") +4. **Dropdown Menu** - Quick access to all available networks + += Network Statistics = + +Each network entry displays: +* Network display name +* Domain and path information +* Total number of sites +* Visual indicator for the current network (✓) + += Keyboard Shortcuts = + +* **Ctrl+Shift+N** - Open network switcher dropdown + += Developer Friendly = + +The plugin provides utility functions for developers: + +* `wpmn_get_network_sites_count($network_id)` - Get site count for a network +* `wpmn_user_can_access_network($user_id, $network_id)` - Check user permissions +* `wpmn_get_network_display_name($network_id)` - Get formatted network name + += Translations = + +The plugin is fully translatable and includes: +* English (default) +* Chinese Simplified (zh_CN) +* More languages coming soon! + +Want to contribute a translation? Visit our [GitHub repository](https://github.com/wpmultisite/wp-multinetwork-adminbar). + +== Installation == + += Minimum Requirements = + +* WordPress 5.0 or greater +* WordPress Multisite enabled +* WP Multi Network plugin installed and activated +* PHP version 7.4 or greater +* MySQL version 5.6 or greater + += Automatic Installation = + +1. Log in to your WordPress admin panel +2. Navigate to Plugins → Add New +3. Search for "WP Multi Network Admin Bar" +4. Click "Install Now" and then "Activate" +5. The plugin will automatically detect your Multi Network setup + += Manual Installation = + +1. Download the plugin zip file +2. Extract the files to your `/wp-content/plugins/wp-multinetwork-adminbar/` directory +3. Activate the plugin through the 'Plugins' menu in WordPress +4. Ensure you have WP Multi Network plugin installed and configured + += Network Activation = + +For Multi Network setups, you should activate this plugin at the network level: + +1. Go to Network Admin → Plugins +2. Find "WP Multi Network Admin Bar" +3. Click "Network Activate" + +== Frequently Asked Questions == + += Does this plugin work with regular WordPress Multisite? = + +This plugin is specifically designed for WP Multi Network environments. While it can detect regular multisite installations, the network switching functionality requires the WP Multi Network plugin to be installed and configured. + += Can I customize the network display names? = + +Yes! The plugin uses the "Site Name" setting from each network's configuration. You can change this in Network Admin → Settings for each individual network. + += How do I hide the network switcher for certain users? = + +The network switcher only appears for users with `manage_network` capability. You can customize this by using WordPress capability management plugins or custom code. + += Does this plugin affect site performance? = + +No, the plugin is designed with performance in mind. It uses WordPress caching to store network statistics and only loads when the admin bar is displayed. + += Can I translate this plugin to my language? = + +Absolutely! The plugin is fully internationalized. You can find translation files in the `/languages/` directory. We welcome community translations on our GitHub repository. + += Is this plugin compatible with other admin bar plugins? = + +Yes, the plugin is designed to work alongside other admin bar modifications. It adds its own menu item without interfering with existing functionality. + += What happens if I deactivate WP Multi Network? = + +The plugin will gracefully detect the absence of WP Multi Network and won't display the network switcher. No errors or conflicts will occur. + +== Screenshots == + +1. **Admin Bar Integration** - The network indicator seamlessly integrated into the WordPress admin bar +2. **Network Dropdown Menu** - Complete network listing with site counts and quick switching +3. **Current Network Highlighting** - Clear visual indication of the active network with checkmark +4. **Mobile Responsive Design** - Optimized display for mobile devices and tablets +5. **Network Statistics Display** - Detailed information showing domain, path, and site counts +6. **Settings Integration** - Network management links for easy administration access + +== Changelog == + += 1.0.0 - 2025-06-15 = +* Initial release +* Network identification in admin bar +* Quick network switching functionality +* Network statistics display +* Performance optimization with caching +* Full internationalization support +* WordPress 6.8 compatibility +* Mobile responsive design +* Accessibility features +* Keyboard shortcuts support + +== Upgrade Notice == + += 1.0.0 = +Initial release of WP Multi Network Admin Bar. This plugin enhances your Multi Network management experience with intuitive network switching and identification features. + +== Support == + +For support, feature requests, and bug reports, please visit: + +* **Documentation**: https://wpmultinetwork.com/document/admin-bar +* **Support Forum**: https://wpmultinetwork.com/support +* **GitHub Issues**: https://github.com/wpmultisite/wp-multinetwork-adminbar/issues + +== Contributing == + +We welcome contributions! Please see our [contributing guidelines](https://github.com/wpmultisite/wp-multinetwork-adminbar/blob/main/CONTRIBUTING.md) on GitHub. + +== Privacy Policy == + +This plugin does not collect, store, or transmit any personal data. It only accesses WordPress network configuration data that is already available to users with appropriate permissions. + +== Credits == + +Developed by the WPMultiNetwork.com team with ❤️ for the WordPress Multi Network community. + +Special thanks to contributors and translators who help make this plugin better for everyone. \ No newline at end of file diff --git a/wp-multinetwork-adminbar.php b/wp-multinetwork-adminbar.php new file mode 100644 index 0000000..8fa05ac --- /dev/null +++ b/wp-multinetwork-adminbar.php @@ -0,0 +1,498 @@ +loadTextDomain(); + + // Check if this is a multi-network environment + if (!$this->isMultiNetwork()) { + return; + } + + // Add admin bar items + add_action('admin_bar_menu', [$this, 'addNetworkInfoToAdminBar'], 100); + + // Enqueue assets + add_action('admin_enqueue_scripts', [$this, 'enqueueAdminAssets']); + add_action('wp_enqueue_scripts', [$this, 'enqueueAdminAssets']); + + // Add AJAX handlers + add_action('wp_ajax_switch_network', [$this, 'handleNetworkSwitch']); + } + + /** + * Load plugin text domain for translations + */ + private function loadTextDomain() { + load_plugin_textdomain( + WPMN_ADMINBAR_TEXT_DOMAIN, + false, + dirname(plugin_basename(__FILE__)) . '/languages' + ); + } + + /** + * Check if this is a multi-network environment + */ + private function isMultiNetwork() { + return is_multisite() && function_exists('get_networks'); + } + + /** + * Add network information to admin bar + */ + public function addNetworkInfoToAdminBar($wp_admin_bar) { + // Only show for users with network management capabilities + if (!current_user_can('manage_network')) { + return; + } + + $current_network = $this->getCurrentNetworkInfo(); + $all_networks = $this->getAllNetworks(); + + if (empty($current_network) || count($all_networks) <= 1) { + return; + } + + // Add parent menu item + $wp_admin_bar->add_menu([ + 'id' => 'wp-multinetwork-switcher', + 'title' => $this->getNetworkDisplayTitle($current_network), + 'href' => '#', + 'meta' => [ + 'class' => 'wp-multinetwork-switcher', + 'title' => sprintf( + __('Current Network: %s', WPMN_ADMINBAR_TEXT_DOMAIN), + $current_network['domain'] + ) + ] + ]); + + // Add network list submenu + foreach ($all_networks as $network) { + $is_current = ($network->id == $current_network['id']); + $site_count = $this->getNetworkSitesCount($network->id); + + $wp_admin_bar->add_menu([ + 'parent' => 'wp-multinetwork-switcher', + 'id' => 'network-' . $network->id, + 'title' => $this->getNetworkMenuTitle($network, $is_current, $site_count), + 'href' => $is_current ? '#' : $this->getNetworkSwitchUrl($network), + 'meta' => [ + 'class' => $is_current ? 'current-network' : 'switch-network', + 'data-network-id' => $network->id, + 'title' => sprintf( + __('Network: %s%s (%d sites)', WPMN_ADMINBAR_TEXT_DOMAIN), + $network->domain, + $network->path, + $site_count + ) + ] + ]); + } + + // Add network admin link + if (current_user_can('manage_network')) { + $wp_admin_bar->add_menu([ + 'parent' => 'wp-multinetwork-switcher', + 'id' => 'network-admin-all', + 'title' => '🔧 ' . __('Manage All Networks', WPMN_ADMINBAR_TEXT_DOMAIN), + 'href' => network_admin_url(), + 'meta' => [ + 'class' => 'network-admin-link' + ] + ]); + } + } + + /** + * Get current network information + */ + private function getCurrentNetworkInfo() { + $current_network = get_network(); + + if (!$current_network) { + return null; + } + + return [ + 'id' => $current_network->id, + 'domain' => $current_network->domain, + 'path' => $current_network->path, + 'site_name' => get_network_option($current_network->id, 'site_name', $current_network->domain) + ]; + } + + /** + * Get all networks + */ + private function getAllNetworks() { + if (!function_exists('get_networks')) { + return []; + } + + return get_networks([ + 'number' => 100, // Limit to avoid performance issues + 'orderby' => 'domain' + ]); + } + + /** + * Get network sites count with caching + */ + private function getNetworkSitesCount($network_id) { + $cache_key = 'wpmn_network_sites_count_' . $network_id; + $count = wp_cache_get($cache_key); + + if (false === $count) { + $sites = get_sites([ + 'network_id' => $network_id, + 'count' => true, + 'number' => 1000 // Reasonable limit + ]); + $count = is_numeric($sites) ? intval($sites) : count($sites); + + // Cache for 5 minutes + wp_cache_set($cache_key, $count, '', 300); + } + + return $count; + } + + /** + * Generate network display title (main admin bar menu) + */ + private function getNetworkDisplayTitle($network_info) { + $site_name = !empty($network_info['site_name']) ? + $network_info['site_name'] : + $network_info['domain']; + + $current_site_count = $this->getNetworkSitesCount($network_info['id']); + + return sprintf( + '🌐 %s (%d)', + esc_html($site_name), + $current_site_count + ); + } + + /** + * Generate network menu title + */ + private function getNetworkMenuTitle($network, $is_current, $site_count) { + $site_name = get_network_option($network->id, 'site_name', $network->domain); + $indicator = $is_current ? '✓ ' : ''; + + return sprintf( + '%s%s (%s)
%s%s', + $indicator, + esc_html($site_name), + sprintf(_n('%d site', '%d sites', $site_count, WPMN_ADMINBAR_TEXT_DOMAIN), $site_count), + esc_html($network->domain), + $network->path !== '/' ? esc_html($network->path) : '' + ); + } + + /** + * Generate network switch URL + */ + private function getNetworkSwitchUrl($network) { + $protocol = is_ssl() ? 'https://' : 'http://'; + $url = $protocol . $network->domain . $network->path; + + // If in admin, try to switch to corresponding admin + if (is_admin()) { + $url .= 'wp-admin/'; + } + + return $url; + } + + /** + * Handle network switch AJAX request + */ + public function handleNetworkSwitch() { + check_ajax_referer('network_switch_nonce', 'nonce'); + + if (!current_user_can('manage_network')) { + wp_die(__('Insufficient permissions.', WPMN_ADMINBAR_TEXT_DOMAIN)); + } + + $network_id = intval($_POST['network_id']); + $network = get_network($network_id); + + if (!$network) { + wp_send_json_error(__('Network does not exist.', WPMN_ADMINBAR_TEXT_DOMAIN)); + } + + $switch_url = $this->getNetworkSwitchUrl($network); + wp_send_json_success(['redirect_url' => $switch_url]); + } + + /** + * Enqueue admin assets + */ + public function enqueueAdminAssets() { + if (!is_admin_bar_showing() || !current_user_can('manage_network')) { + return; + } + + // Add inline styles + $css = $this->getInlineCSS(); + wp_add_inline_style('admin-bar', $css); + + // Add inline scripts + $js = $this->getInlineJS(); + wp_add_inline_script('jquery', $js); + } + + /** + * Get inline CSS + */ + private function getInlineCSS() { + return ' + #wpadminbar .wp-multinetwork-switcher .ab-item { + padding: 0 10px !important; + } + + #wpadminbar .network-indicator { + font-size: 16px; + margin-right: 5px; + } + + #wpadminbar .network-name { + font-weight: 600; + } + + #wpadminbar .network-count { + font-size: 12px; + opacity: 0.8; + margin-left: 5px; + } + + #wpadminbar .wp-multinetwork-switcher .ab-submenu { + min-width: 300px; + } + + #wpadminbar .wp-multinetwork-switcher .ab-submenu .ab-item { + line-height: 1.3; + padding: 8px 12px !important; + white-space: normal; + } + + #wpadminbar .current-network .ab-item { + background-color: rgba(240, 245, 250, 0.1) !important; + color: #72aee6 !important; + } + + #wpadminbar .switch-network:hover .ab-item { + background-color: #0073aa !important; + color: #fff !important; + } + + #wpadminbar .site-count { + font-size: 11px; + opacity: 0.8; + font-weight: normal; + } + + #wpadminbar .network-admin-link { + border-top: 1px solid rgba(255,255,255,0.2); + margin-top: 5px; + padding-top: 5px; + } + + #wpadminbar .network-admin-link .ab-item { + color: #72aee6 !important; + font-weight: 600; + } + + /* WordPress 6.8 compatibility */ + @media screen and (max-width: 782px) { + #wpadminbar .wp-multinetwork-switcher .ab-submenu { + min-width: 280px; + left: -120px; + } + } + '; + } + + /** + * Get inline JavaScript + */ + private function getInlineJS() { + $nonce = wp_create_nonce('network_switch_nonce'); + $switching_text = __('Switching...', WPMN_ADMINBAR_TEXT_DOMAIN); + + return " + jQuery(document).ready(function($) { + // Network switching functionality + $('.switch-network a').on('click', function(e) { + var href = $(this).attr('href'); + if (href && href !== '#') { + // Add loading indicator + var \$item = $(this).closest('.switch-network').find('.ab-item'); + \$item.append(' ({$switching_text})'); + + // Proceed with navigation + window.location.href = href; + } + }); + + // Keyboard shortcut: Ctrl+Shift+N to open network switcher + $(document).keydown(function(e) { + if (e.ctrlKey && e.shiftKey && e.keyCode === 78) { + e.preventDefault(); + $('#wp-multinetwork-switcher').trigger('click'); + } + }); + + // Add accessibility attributes + $('#wp-multinetwork-switcher').attr({ + 'role': 'menubar', + 'aria-label': '" . esc_js(__('Network Switcher', WPMN_ADMINBAR_TEXT_DOMAIN)) . "' + }); + + $('#wp-multinetwork-switcher .ab-submenu').attr('role', 'menu'); + $('#wp-multinetwork-switcher .ab-submenu li').attr('role', 'menuitem'); + }); + "; + } +} + +// Initialize plugin +WP_MultiNetwork_AdminBar::getInstance(); + +/** + * Activation hook - Check requirements + */ +register_activation_hook(__FILE__, function() { + if (!is_multisite()) { + deactivate_plugins(plugin_basename(__FILE__)); + wp_die( + __('This plugin requires WordPress Multisite to be enabled.', WPMN_ADMINBAR_TEXT_DOMAIN), + __('Plugin Activation Error', WPMN_ADMINBAR_TEXT_DOMAIN), + ['back_link' => true] + ); + } + + // Check WordPress version + global $wp_version; + if (version_compare($wp_version, '5.0', '<')) { + deactivate_plugins(plugin_basename(__FILE__)); + wp_die( + __('This plugin requires WordPress 5.0 or higher.', WPMN_ADMINBAR_TEXT_DOMAIN), + __('Plugin Activation Error', WPMN_ADMINBAR_TEXT_DOMAIN), + ['back_link' => true] + ); + } +}); + +/** + * Deactivation hook - Clean up + */ +register_deactivation_hook(__FILE__, function() { + // Clear any cached data + wp_cache_flush(); +}); + +/** + * Utility function: Get network sites count (public API) + */ +function wpmn_get_network_sites_count($network_id) { + if (!is_multisite() || !function_exists('get_sites')) { + return 0; + } + + $sites = get_sites([ + 'network_id' => $network_id, + 'count' => true, + 'number' => 1000 + ]); + + return is_numeric($sites) ? intval($sites) : count($sites); +} + +/** + * Utility function: Check if user can access network + */ +function wpmn_user_can_access_network($user_id, $network_id) { + $user = get_userdata($user_id); + if (!$user) { + return false; + } + + // Check if user is super admin + if (is_super_admin($user_id)) { + return true; + } + + // Check if user has access to any sites in this network + $sites = get_sites([ + 'network_id' => $network_id, + 'number' => 100 + ]); + + foreach ($sites as $site) { + if (is_user_member_of_blog($user_id, $site->blog_id)) { + return true; + } + } + + return false; +} + +/** + * Utility function: Get network display name + */ +function wpmn_get_network_display_name($network_id) { + $network = get_network($network_id); + if (!$network) { + return ''; + } + + $site_name = get_network_option($network_id, 'site_name'); + return !empty($site_name) ? $site_name : $network->domain; +} \ No newline at end of file