PluginProbe
Version Info – Server Health Monitor, PHP & MySQL Version Display, Environment Indicators / trunk
Version Info – Server Health Monitor, PHP & MySQL Version Display, Environment Indicators vtrunk
2.1.0 2.0.3 2.0.2 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.3.3 2.0.0 2.0.1
version-info / includes / AdminBar.php

AdminBar.php in Version Info – Server Health Monitor, PHP & MySQL Version Display, Environment Indicators trunk, at includes/AdminBar.php

169 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:disable WordPress.Files.FileName -- PSR-4 class file naming; renaming would break the autoloader.
2
3
4 namespace GauchoPlugins\VersionInfo;
5
6 defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
7
8 /**
9 * Admin-bar version nodes plus the shared "Copy as Markdown" clipboard handler.
10 */
11 class AdminBar {
12
13 /**
14 * Hooks the admin-bar nodes and the clipboard-handler output.
15 */
16 public function register() {
17 add_action( 'admin_bar_menu', array( $this, 'add_nodes' ), 100 );
18 // The admin bar also renders on the front-end for logged-in users, so
19 // the clipboard handler prints on both footers (it self-guards).
20 add_action( 'admin_footer', array( $this, 'print_copy_js' ) );
21 add_action( 'wp_footer', array( $this, 'print_copy_js' ) );
22 }
23
24 /**
25 * Adds the version-info nodes to the admin bar.
26 *
27 * @param \WP_Admin_Bar $wp_admin_bar Admin bar instance.
28 */
29 public function add_nodes( \WP_Admin_Bar $wp_admin_bar ) {
30 if ( ! Plugin::current_user_can_view() ) {
31 return;
32 }
33
34 $nodes = array();
35
36 if ( get_option( 'version_info_show_admin_bar', false ) ) {
37 $nodes['version_info_admin_bar'] = array(
38 'id' => 'version_info_admin_bar',
39 'title' => $this->get_version_string(),
40 'parent' => 'top-secondary',
41 );
42 $nodes['version_info_copy_md'] = array(
43 'id' => 'version_info_copy_md',
44 'parent' => 'version_info_admin_bar',
45 'title' => __( 'Copy as Markdown', 'version-info' ),
46 'href' => '#',
47 );
48 }
49
50 /**
51 * Filtered admin-bar node definitions.
52 *
53 * @var array<string, array{id: string, title: string, parent?: string, meta?: array}> $nodes
54 */
55 $nodes = apply_filters( 'version_info_admin_bar_nodes', $nodes );
56
57 foreach ( $nodes as $node ) {
58 $wp_admin_bar->add_node( $node );
59 }
60 }
61
62 /**
63 * Builds the admin-bar version summary string.
64 */
65 private function get_version_string() {
66 global $wpdb;
67
68 $wp_version = apply_filters( 'version_info_wp_version', get_bloginfo( 'version' ) );
69 $php_version = apply_filters( 'version_info_php_version', phpversion() );
70 $server_software = apply_filters(
71 'version_info_server_software',
72 sanitize_text_field( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : __( 'Unknown', 'version-info' ) )
73 );
74 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- reading the MySQL server version; no WP API exists and the value is not site data.
75 $mysql_version = apply_filters( 'version_info_mysql_version', (string) $wpdb->get_var( 'SELECT VERSION()' ) );
76
77 $details = sprintf(
78 /* translators: %1$s: WP version, %2$s: PHP version, %3$s: server software, %4$s: MySQL version */
79 __( 'WordPress %1$s | PHP %2$s | Web Server %3$s | MySQL %4$s', 'version-info' ),
80 esc_html( $wp_version ),
81 esc_html( $php_version ),
82 esc_html( $server_software ),
83 esc_html( $mysql_version )
84 );
85
86 if ( get_option( 'version_info_show_memory', true ) ) {
87 $memory_text = SystemInfo::memory_text();
88 if ( '' !== $memory_text ) {
89 /* translators: %s: PHP memory usage summary, e.g. "24.6 MB of 256 MB (9.6%)" */
90 $details .= sprintf( __( ' | Mem %s', 'version-info' ), esc_html( $memory_text ) );
91 }
92 }
93
94 $eol_alert = SystemInfo::php_eol_alert_text();
95 if ( '' !== $eol_alert ) {
96 $details .= ' | ' . esc_html( $eol_alert );
97 }
98
99 return $details;
100 }
101
102 /**
103 * Clipboard handler for the "Copy as Markdown" control (admin-bar node
104 * and dashboard-widget button). Inline vanilla JS — the plugin enqueues
105 * no assets by design; see the General-tab script for the precedent.
106 */
107 public function print_copy_js() {
108 if ( ! Plugin::current_user_can_view()
109 || ( ! get_option( 'version_info_show_admin_bar', false ) && ! get_option( 'version_info_show_dashboard_widget', false ) ) ) {
110 return;
111 }
112 if ( ! is_admin() && ! is_admin_bar_showing() ) {
113 return;
114 }
115
116 // JSON with hex flags makes `</script>` breakout impossible and keeps
117 // multi-line payloads intact (esc_js() would mangle the newlines).
118 $json = wp_json_encode( SystemInfo::markdown_table(), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
119 if ( false === $json ) {
120 // Bad UTF-8 somewhere in the payload — the control becomes a no-op.
121 return;
122 }
123 ?>
124 <script>
125 (function () {
126 var payload = <?php echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON-encoded with hex flags above. ?>;
127 var done = function ( el, ok ) {
128 var original = el.textContent;
129 el.textContent = ok
130 ? '<?php echo esc_js( __( 'Copied!', 'version-info' ) ); ?>'
131 : '<?php echo esc_js( __( 'Copy failed', 'version-info' ) ); ?>';
132 setTimeout( function () { el.textContent = original; }, 2000 );
133 };
134 // Textarea + execCommand fallback: WP 4.7-era browsers and
135 // plain-HTTP admins have no navigator.clipboard.
136 var fallbackCopy = function () {
137 var area = document.createElement( 'textarea' ), ok = false;
138 area.value = payload;
139 area.style.cssText = 'position:fixed;left:-9999px;';
140 document.body.appendChild( area );
141 area.select();
142 try { ok = document.execCommand( 'copy' ); } catch ( e ) { ok = false; }
143 document.body.removeChild( area );
144 return ok;
145 };
146 var bind = function ( el, labelEl ) {
147 if ( ! el ) { return; }
148 el.addEventListener( 'click', function ( event ) {
149 event.preventDefault();
150 var label = labelEl || el;
151 if ( window.isSecureContext && navigator.clipboard && navigator.clipboard.writeText ) {
152 navigator.clipboard.writeText( payload ).then(
153 function () { done( label, true ); },
154 function () { done( label, fallbackCopy() ); }
155 );
156 } else {
157 done( label, fallbackCopy() );
158 }
159 } );
160 };
161 var node = document.getElementById( 'wp-admin-bar-version_info_copy_md' );
162 bind( node, node ? node.querySelector( '.ab-item' ) : null );
163 bind( document.getElementById( 'vi-copy-md' ) );
164 }());
165 </script>
166 <?php
167 }
168 }
169