load_textdomain(); // Get server information. $server_info = $this->get_server_info(); // Build icon only title (no text, just icon). $icon_title = ''; // Add main menu item to admin bar (right side). // Using 'top-secondary' as parent ensures it appears on the right side. $wp_admin_bar->add_node( array( 'id' => 'abs_server_info', 'title' => $icon_title, 'parent' => 'top-secondary', 'meta' => array( 'title' => esc_html__( 'Server Information', 'admin-bar-server-info' ), 'class' => 'abs-server-info', ), ) ); // Add submenu items for dropdown (visible on screens > 1500px). $submenu_items = array( array( 'id' => 'abs_php_info', /* translators: %s: PHP version */ 'title' => sprintf( esc_html__( 'PHP: %s', 'admin-bar-server-info' ), esc_html( $server_info['php_version'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_sapi_info', /* translators: %s: PHP SAPI (Server API) */ 'title' => sprintf( esc_html__( 'SAPI: %s', 'admin-bar-server-info' ), esc_html( $server_info['sapi'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_os_info', /* translators: %s: Operating system */ 'title' => sprintf( esc_html__( 'OS: %s', 'admin-bar-server-info' ), esc_html( $server_info['os'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_exec_time', /* translators: %s: Maximum execution time */ 'title' => sprintf( esc_html__( 'Max Execution Time: %s', 'admin-bar-server-info' ), esc_html( $server_info['max_execution_time'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_upload_size', /* translators: %s: Maximum upload size */ 'title' => sprintf( esc_html__( 'Max Upload: %s', 'admin-bar-server-info' ), esc_html( $server_info['max_upload_size'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_memory_usage', /* translators: %s: Memory usage information */ 'title' => sprintf( esc_html__( 'Memory Usage: %s', 'admin-bar-server-info' ), esc_html( $server_info['memory_usage'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_wp_memory', /* translators: %s: WordPress memory limit */ 'title' => sprintf( esc_html__( 'WP Memory Limit: %s', 'admin-bar-server-info' ), esc_html( $server_info['wp_memory_limit'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_server_software', /* translators: %s: Server software name */ 'title' => sprintf( esc_html__( 'Server: %s', 'admin-bar-server-info' ), esc_html( $server_info['server_software'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_db_version', /* translators: %s: Database version */ 'title' => sprintf( esc_html__( 'Database: %s', 'admin-bar-server-info' ), esc_html( $server_info['db_version'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_server_ip', /* translators: %s: Server IP address */ 'title' => sprintf( esc_html__( 'Server IP: %s', 'admin-bar-server-info' ), esc_html( $server_info['server_ip'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_wp_version', /* translators: %s: WordPress version */ 'title' => sprintf( esc_html__( 'WordPress: %s', 'admin-bar-server-info' ), esc_html( $server_info['wp_version'] ) ), 'parent' => 'abs_server_info', ), array( 'id' => 'abs_disk_space', /* translators: %s: Disk space information */ 'title' => sprintf( esc_html__( 'Disk Space: %s', 'admin-bar-server-info' ), esc_html( $server_info['disk_space'] ) ), 'parent' => 'abs_server_info', ), ); // Add all submenu items. foreach ( $submenu_items as $item ) { $wp_admin_bar->add_node( $item ); } } /** * Load plugin textdomain for translations. * * Loads translations from plugin's languages directory. * WordPress.org will override with translations from wp-content/languages/plugins/ if available. * This ensures compatibility with both local development and WordPress.org. * * @since 1.2.0 */ public function load_textdomain() { $domain = 'admin-bar-server-info'; // Get current locale. $locale = get_locale(); if ( empty( $locale ) ) { $locale = determine_locale(); } // First, try to load from WordPress.org languages directory (if plugin is in repo). $mofile_global = WP_LANG_DIR . '/plugins/' . $domain . '-' . $locale . '.mo'; // Then, try plugin's local languages directory. $mofile_local = plugin_dir_path( __FILE__ ) . 'languages/' . $domain . '-' . $locale . '.mo'; // Load from global location first (WordPress.org), then fallback to local. $loaded = false; if ( file_exists( $mofile_global ) ) { $loaded = load_textdomain( $domain, $mofile_global ); } if ( ! $loaded && file_exists( $mofile_local ) ) { $loaded = load_textdomain( $domain, $mofile_local ); } return $loaded; } /** * Enqueue styles for admin bar. * * @since 1.0.3 */ public function enqueue_styles() { // Only enqueue styles for administrators. if ( ! current_user_can( 'manage_options' ) ) { return; } // Ensure Dashicons are loaded (dependency for admin-bar, but ensure it's available). wp_enqueue_style( 'dashicons' ); $css_file = plugin_dir_url( __FILE__ ) . 'assets/css/admin-bar-server-info.css'; wp_enqueue_style( 'admin-bar-server-info', $css_file, array( 'dashicons' ), self::VERSION ); } /** * Get server and environment information. * * @since 1.0.0 * @return array Array containing server information. */ private function get_server_info() { global $wpdb; $info = array(); // Get PHP version. $info['php_version'] = $this->get_php_version(); // Get database version. $info['db_version'] = $this->get_database_version( $wpdb ); // Get server software. $info['server_software'] = $this->get_server_software(); // Get WordPress version. $info['wp_version'] = get_bloginfo( 'version' ); // Get server IP address. $info['server_ip'] = $this->get_server_ip(); // Get memory usage. $info['memory_usage'] = $this->get_memory_usage(); // Get WordPress memory limit. $info['wp_memory_limit'] = $this->get_wp_memory_limit(); // Get operating system. $info['os'] = $this->get_operating_system(); // Get PHP SAPI. $info['sapi'] = $this->get_php_sapi(); // Get max execution time. $info['max_execution_time'] = $this->get_max_execution_time(); // Get max upload size. $info['max_upload_size'] = $this->get_max_upload_size(); // Get disk space information. $info['disk_space'] = $this->get_disk_space(); return $info; } /** * Get PHP version. * * @since 1.0.0 * @return string PHP version with architecture info. */ private function get_php_version() { $php_version = PHP_VERSION; // Get architecture (32 or 64 bit). $php_bits = PHP_INT_SIZE * 8; // Format: "8.3.29 @64BitOS" (matching the original plugin format). return $php_version . ' @' . $php_bits . 'BitOS'; } /** * Get database version. * * @since 1.0.0 * @param wpdb $wpdb WordPress database object. * @return string Database version. */ private function get_database_version( $wpdb ) { // Use WordPress method to get database server info (recommended approach). // This avoids direct database queries and uses WordPress caching. if ( method_exists( $wpdb, 'db_server_info' ) ) { $db_version_full = $wpdb->db_server_info(); } elseif ( method_exists( $wpdb, 'db_version' ) ) { // Fallback to db_version() if db_server_info() is not available. $db_version_full = $wpdb->db_version(); } else { $db_version_full = ''; } if ( empty( $db_version_full ) ) { return esc_html__( 'Unknown', 'admin-bar-server-info' ); } // Check if it's MariaDB (case-insensitive search). $is_mariadb = ( stripos( $db_version_full, 'mariadb' ) !== false ); // Extract version numbers (major.minor). // MariaDB version format: "10.11.2-MariaDB" or similar. // MySQL version format: "8.0.35" or similar. preg_match( '/(\d+)\.(\d+)/', $db_version_full, $matches ); if ( ! empty( $matches ) && count( $matches ) >= 3 ) { $major = $matches[1]; $minor = $matches[2]; $db_type = $is_mariadb ? 'MariaDB' : 'MySQL'; return $db_type . ' ' . $major . '.' . $minor; } // Fallback: return as-is with detected type. $db_type = $is_mariadb ? 'MariaDB' : 'MySQL'; return $db_type . ' ' . $db_version_full; } /** * Get server software name. * * @since 1.0.0 * @return string Server software name. */ private function get_server_software() { // Check if SERVER_SOFTWARE is available. if ( ! isset( $_SERVER['SERVER_SOFTWARE'] ) || empty( $_SERVER['SERVER_SOFTWARE'] ) ) { return esc_html__( 'Unknown', 'admin-bar-server-info' ); } $server_software = sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ); // Detect common server software. if ( stripos( $server_software, 'apache' ) !== false ) { return 'Apache'; } elseif ( stripos( $server_software, 'nginx' ) !== false ) { return 'Nginx'; } elseif ( stripos( $server_software, 'litespeed' ) !== false ) { return 'LiteSpeed'; } elseif ( stripos( $server_software, 'iis' ) !== false ) { return 'IIS'; } elseif ( stripos( $server_software, 'caddy' ) !== false ) { return 'Caddy'; } // If no known server detected, return first part of SERVER_SOFTWARE. $parts = explode( '/', $server_software ); if ( ! empty( $parts[0] ) ) { return esc_html( trim( $parts[0] ) ); } return esc_html__( 'Unknown', 'admin-bar-server-info' ); } /** * Get server IP address with hostname. * * @since 1.0.3 * @return string Server IP address with hostname in parentheses. */ private function get_server_ip() { // Try SERVER_ADDR first (standard for most servers). $server_ip = ! empty( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : ''; // Fallback to LOCAL_ADDR for IIS servers. if ( empty( $server_ip ) && ! empty( $_SERVER['LOCAL_ADDR'] ) ) { $server_ip = sanitize_text_field( wp_unslash( $_SERVER['LOCAL_ADDR'] ) ); } // If still empty, try to get from hostname. if ( empty( $server_ip ) && function_exists( 'gethostname' ) ) { $hostname = gethostname(); if ( $hostname ) { $ip = gethostbyname( $hostname ); if ( $ip !== $hostname ) { $server_ip = $ip; } } } // Get hostname for display (matching the original plugin format). $hostname = ''; if ( function_exists( 'gethostname' ) ) { $hostname = gethostname(); } // Format: "IP 172.23.0.3 (hostname)" or just "IP 172.23.0.3" if no hostname. if ( empty( $server_ip ) ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } $ip_display = esc_html( $server_ip ); if ( ! empty( $hostname ) ) { $ip_display .= ' (' . esc_html( $hostname ) . ')'; } return $ip_display; } /** * Get memory usage information. * * @since 1.0.3 * @return string Memory usage formatted string. */ private function get_memory_usage() { // Get memory limit (current PHP limit, which WordPress may have adjusted). $memory_limit = ini_get( 'memory_limit' ); // Convert memory limit to bytes using our own converter for maximum compatibility. $memory_limit_bytes = $this->convert_to_bytes( $memory_limit ); // Get peak memory usage. $memory_usage_bytes = function_exists( 'memory_get_peak_usage' ) ? memory_get_peak_usage( true ) : 0; // Handle unlimited memory (-1). if ( -1 === $memory_limit_bytes ) { // Unlimited memory - show usage only. if ( empty( $memory_usage_bytes ) ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } $memory_usage_mb = round( $memory_usage_bytes / 1024 / 1024, 2 ); return sprintf( /* translators: 1: Memory usage in MB, 2: "Unlimited" text */ esc_html__( '%1$s MB (%2$s)', 'admin-bar-server-info' ), number_format_i18n( $memory_usage_mb, 2 ), esc_html__( 'Unlimited', 'admin-bar-server-info' ) ); } // Handle invalid values. if ( empty( $memory_usage_bytes ) || empty( $memory_limit_bytes ) || $memory_limit_bytes <= 0 ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } // Convert to MB for display. $memory_usage_mb = round( $memory_usage_bytes / 1024 / 1024, 2 ); $memory_limit_mb = round( $memory_limit_bytes / 1024 / 1024, 2 ); // Calculate percentage. $memory_percent = round( ( $memory_usage_bytes / $memory_limit_bytes ) * 100, 0 ); // Format: "used/total MB (XX%)" - matching the original plugin format more closely. return sprintf( /* translators: 1: Memory usage in MB, 2: Memory limit in MB, 3: Percentage */ esc_html__( '%1$s/%2$s MB (%3$d%%)', 'admin-bar-server-info' ), number_format_i18n( $memory_usage_mb, 2 ), number_format_i18n( $memory_limit_mb, 2 ), $memory_percent ); } /** * Convert memory size string to bytes. * * @since 1.0.3 * @param string $size Memory size string (e.g., "128M", "256K", "-1" for unlimited). * @return int Size in bytes, or -1 for unlimited. */ private function convert_to_bytes( $size ) { $size = trim( $size ); // Handle empty or invalid values. if ( empty( $size ) ) { return 0; } // Handle unlimited memory (-1). if ( '-1' === $size ) { return -1; } // Get the last character to determine unit. $last = strtolower( substr( $size, -1 ) ); $value = (int) $size; // Convert based on unit (G, M, K). switch ( $last ) { case 'g': $value *= 1024; // Fall through. case 'm': $value *= 1024; // Fall through. case 'k': $value *= 1024; } return $value; } /** * Get WordPress memory limit. * * @since 1.0.3 * @return string WordPress memory limit formatted string. */ private function get_wp_memory_limit() { // Check if WP_MEMORY_LIMIT constant is defined. if ( ! defined( 'WP_MEMORY_LIMIT' ) ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } $wp_limit = WP_MEMORY_LIMIT; // Convert to bytes for formatting. $wp_limit_bytes = $this->convert_to_bytes( $wp_limit ); if ( empty( $wp_limit_bytes ) || $wp_limit_bytes <= 0 ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } // Use WordPress size_format function if available, otherwise format manually. if ( function_exists( 'size_format' ) ) { return size_format( $wp_limit_bytes ); } // Manual formatting if size_format is not available. $wp_limit_mb = round( $wp_limit_bytes / 1024 / 1024, 0 ); /* translators: %s: Memory limit in MB */ return sprintf( esc_html__( '%s MB', 'admin-bar-server-info' ), number_format_i18n( $wp_limit_mb ) ); } /** * Get operating system name. * * @since 1.0.3 * @return string Operating system name. */ private function get_operating_system() { // Try php_uname first (more detailed). if ( function_exists( 'php_uname' ) ) { $os = php_uname( 's' ); if ( ! empty( $os ) ) { return esc_html( $os ); } } // Fallback to PHP_OS constant. if ( defined( 'PHP_OS' ) ) { return esc_html( PHP_OS ); } return esc_html__( 'Unknown', 'admin-bar-server-info' ); } /** * Get PHP SAPI (Server API). * * @since 1.0.3 * @return string PHP SAPI name (shortened for common values). */ private function get_php_sapi() { if ( function_exists( 'php_sapi_name' ) ) { $sapi = php_sapi_name(); if ( ! empty( $sapi ) ) { // Shorten common SAPIs to avoid redundancy. switch ( $sapi ) { case 'apache2handler': return 'mod_php'; case 'fpm-fcgi': return 'fpm'; case 'cgi-fcgi': return 'cgi'; default: return esc_html( $sapi ); } } } return esc_html__( 'Unknown', 'admin-bar-server-info' ); } /** * Get max execution time. * * @since 1.0.3 * @return string Max execution time in seconds. */ private function get_max_execution_time() { $max_exec_time = ini_get( 'max_execution_time' ); // Handle unlimited (0 or -1). if ( empty( $max_exec_time ) || $max_exec_time < 0 ) { return esc_html__( 'Unlimited', 'admin-bar-server-info' ); } /* translators: %s: Execution time in seconds */ return sprintf( esc_html__( '%s s', 'admin-bar-server-info' ), esc_html( $max_exec_time ) ); } /** * Get max upload size. * * @since 1.0.3 * @return string Max upload size formatted. */ private function get_max_upload_size() { $upload_max = ini_get( 'upload_max_filesize' ); if ( empty( $upload_max ) ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } // Return as-is (already formatted like "64M", "2M", etc.). return esc_html( $upload_max ); } /** * Get disk space information. * * @since 1.2.0 * @return string Disk space formatted string (free/total with percentage). */ private function get_disk_space() { // Get WordPress root directory (usually where wp-config.php is located). $path = ABSPATH; // Try to get disk free space. $free_space = false; if ( function_exists( 'disk_free_space' ) ) { $free_space = @disk_free_space( $path ); } // Try to get total disk space. $total_space = false; if ( function_exists( 'disk_total_space' ) ) { $total_space = @disk_total_space( $path ); } // If we couldn't get disk information, return N/A. if ( false === $free_space || false === $total_space ) { return esc_html__( 'N/A', 'admin-bar-server-info' ); } // Convert to GB for better readability. $free_gb = round( $free_space / 1024 / 1024 / 1024, 2 ); $total_gb = round( $total_space / 1024 / 1024 / 1024, 2 ); // Calculate used space. $used_space = $total_space - $free_space; $used_gb = round( $used_space / 1024 / 1024 / 1024, 2 ); // Calculate percentage used. $percent_used = round( ( $used_space / $total_space ) * 100, 1 ); // Format: "free/total GB (XX% used)" or "free/total GB (XX% free)". // Show percentage used for better understanding. return sprintf( /* translators: 1: Free disk space in GB, 2: Total disk space in GB, 3: Percentage used */ esc_html__( '%1$s/%2$s GB (%3$s%% used)', 'admin-bar-server-info' ), number_format_i18n( $free_gb, 2 ), number_format_i18n( $total_gb, 2 ), number_format_i18n( $percent_used, 1 ) ); } } /** * Initialize the plugin. * * @since 1.0.0 */ function admin_bar_server_info_init() { new Admin_Bar_Server_Info(); } add_action( 'init', 'admin_bar_server_info_init' );