PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 9.0.2
Admin and Site Enhancements (ASE) v9.0.2
9.1.1 9.1.0 9.0.2 9.0.1 9.0.0 8.9.2 8.9.1 8.9.0 8.8.8 8.8.7 8.8.6 8.8.5 8.8.4 8.8.3 8.8.2 8.8.1 8.8.0 8.7.3 8.7.2 8.7.1 8.2.1 8.2.2 8.2.3 8.3.0 8.3.1 8.3.2 8.4.0 8.4.1 8.4.2 8.5.0 8.5.1 8.5.2 8.6.0 8.6.1 8.6.2 8.7.0 5.0.1 5.0.2 5.0.2.1 5.0.2.2 5.0.2.3 5.0.2.4 5.1.0 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.8.0 5.8.1 6.0.0 6.0.3 6.0.4 6.0.5 6.0.5.1 6.0.6 6.0.7 6.0.8.1 6.1.0 6.1.3 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.3.0 6.3.1 6.3.2 6.4.0 6.5.0 6.5.1 6.6.0 6.7.0 6.8.0 6.8.2 6.8.3 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13.1 6.9.13.2 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.2 7.0.2.1 7.0.2.2 7.0.2.3 7.0.3 7.1.0 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2.0 7.2.1 7.3.0 7.3.1 7.3.2 7.3.3 7.4.0 7.4.2 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8 7.5.0 7.5.1 7.5.2 7.5.3 7.5.4 7.6.0 7.6.1 7.6.1.1 7.6.10 7.6.11 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.7.1 7.6.8 7.6.9 7.7.0 7.8.0 7.8.1 7.8.10 7.8.11 7.8.12 7.8.13 7.8.14 7.8.15 7.8.16 7.8.17 7.8.18 7.8.2 7.8.3 7.8.4 7.8.5 7.8.5.1 7.8.6 7.8.7 7.8.8 7.8.9 7.9.0 7.9.1 7.9.10 7.9.11 7.9.2 7.9.3 7.9.4 7.9.5 7.9.6 7.9.7 7.9.8 7.9.9 8.0.0 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.1.0 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 3.6.1 3.7.0 3.8.0 3.9.0 3.9.1 3.9.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.9.0 4.9.1 4.9.2 4.9.3 5.0.0
admin-site-enhancements / classes / class-admin-menu-svg-icon-mask.php
admin-site-enhancements / classes Last commit date
class-activation.php 2 weeks ago class-admin-menu-organizer.php 2 weeks ago class-admin-menu-svg-icon-mask.php 2 weeks ago class-auto-publish-posts-with-missed-schedule.php 2 weeks ago class-avif-upload.php 2 weeks ago class-captcha-protection.php 2 weeks ago class-change-login-url.php 2 weeks ago class-cleanup-admin-bar.php 2 weeks ago class-common-methods.php 2 weeks ago class-content-duplication.php 2 weeks ago class-content-order.php 2 weeks ago class-custom-admin-footer-text.php 2 weeks ago class-custom-body-class.php 2 weeks ago class-custom-css.php 2 weeks ago class-custom-nav-menu-items-in-new-tab.php 2 weeks ago class-deactivation.php 2 weeks ago class-disable-author-archives.php 2 weeks ago class-disable-comments.php 2 weeks ago class-disable-dashboard-widgets.php 2 weeks ago class-disable-embeds.php 2 weeks ago class-disable-feeds.php 2 weeks ago class-disable-gutenberg.php 2 weeks ago class-disable-rest-api.php 2 weeks ago class-disable-smaller-components.php 2 weeks ago class-disable-updates.php 2 weeks ago class-disable-user-account.php 2 weeks ago class-disable-xml-rpc.php 2 weeks ago class-display-system-summary.php 2 weeks ago class-email-address-obfuscator.php 2 weeks ago class-email-delivery.php 2 weeks ago class-enhance-list-tables.php 2 weeks ago class-external-permalinks.php 2 weeks ago class-heartbeat-control.php 2 weeks ago class-hide-admin-bar.php 2 weeks ago class-hide-admin-notices.php 2 weeks ago class-image-sizes-panel.php 2 weeks ago class-image-upload-control.php 2 weeks ago class-insert-head-body-footer-code.php 2 weeks ago class-last-login-column.php 2 weeks ago class-limit-login-attempts.php 2 weeks ago class-login-id-type.php 2 weeks ago class-login-logout-menu.php 2 weeks ago class-maintenance-mode.php 2 weeks ago class-manage-ads-appads-txt.php 2 weeks ago class-manage-robots-txt.php 2 weeks ago class-media-files-visibility-control.php 2 weeks ago class-media-replacement.php 2 weeks ago class-multiple-user-roles.php 2 weeks ago class-navigation-menu-duplicator.php 2 weeks ago class-obfuscate-author-slugs.php 2 weeks ago class-open-external-links-in-new-tab.php 2 weeks ago class-password-protection.php 2 weeks ago class-redirect-after-login.php 2 weeks ago class-redirect-after-logout.php 2 weeks ago class-redirect-fourofour.php 2 weeks ago class-registration-date-column.php 2 weeks ago class-revisions-control.php 2 weeks ago class-search-engines-visibility.php 2 weeks ago class-settings-fields-render.php 2 weeks ago class-settings-sanitization.php 2 weeks ago class-settings-sections-fields.php 2 weeks ago class-show-custom-taxonomy-filters.php 2 weeks ago class-site-identity-on-login-page.php 2 weeks ago class-svg-upload.php 2 weeks ago class-third-party-compat.php 2 weeks ago class-various-admin-ui-enhancements.php 2 weeks ago class-view-admin-as-role.php 2 weeks ago class-wider-admin-menu.php 2 weeks ago class-wp-config-transformer.php 2 weeks ago
class-admin-menu-svg-icon-mask.php
236 lines
1 <?php
2 /**
3 * Shared helper for rendering SVG admin menu icons with correct colors on first paint.
4 *
5 * WordPress renders `menu_icon` SVG data URIs as <img> initially, and then core's
6 * `svg-painter` inlines/recolors them, causing a visible "black → scheme color" flash.
7 * This helper pre-empts that by forcing WordPress to use the `.wp-menu-image:before`
8 * pseudo-element (via a Dashicon placeholder) and then applying the SVG as a CSS mask.
9 *
10 * @since 7.6.0
11 */
12
13 namespace ASENHA\Classes;
14
15 class Admin_Menu_Svg_Icon_Mask {
16
17 /**
18 * Registered SVG data URIs keyed by post type key.
19 *
20 * @since 7.6.0
21 * @var array<string,string>
22 */
23 private static $post_type_svgs = array();
24
25 /**
26 * Registered SVG data URIs keyed by top-level menu slug (from add_menu_page()).
27 *
28 * @since 7.6.0
29 * @var array<string,string>
30 */
31 private static $toplevel_menu_slug_svgs = array();
32
33 /**
34 * Registered SVG data URIs keyed by a substring to match against `href`.
35 *
36 * This is useful for menu slugs that are full URLs/queries (e.g. `post.php?post=123&action=edit`).
37 *
38 * @since 7.6.0
39 * @var array<string,string>
40 */
41 private static $href_contains_svgs = array();
42
43 /**
44 * Check whether a string is an SVG data URI that WordPress would render as an <img>.
45 *
46 * @since 7.6.0
47 *
48 * @param mixed $value Potential menu icon.
49 * @return bool
50 */
51 public static function is_svg_data_uri( $value ) {
52 return is_string( $value ) && ( 0 === strpos( $value, 'data:image/svg+xml' ) );
53 }
54
55 /**
56 * Register an SVG icon for a post type's admin menu entry.
57 *
58 * @since 7.6.0
59 *
60 * @param string $post_type Post type key.
61 * @param string $svg_data_uri SVG data URI.
62 * @return void
63 */
64 public static function register_post_type_svg_icon( $post_type, $svg_data_uri ) {
65 $post_type = sanitize_key( (string) $post_type );
66 $svg_data_uri = trim( (string) $svg_data_uri );
67
68 if ( '' === $post_type || '' === $svg_data_uri ) {
69 return;
70 }
71
72 if ( ! self::is_svg_data_uri( $svg_data_uri ) ) {
73 return;
74 }
75
76 self::$post_type_svgs[ $post_type ] = $svg_data_uri;
77 }
78
79 /**
80 * Register an SVG icon for a top-level menu entry created by add_menu_page().
81 *
82 * @since 7.6.0
83 *
84 * @param string $menu_slug Menu slug passed to add_menu_page().
85 * @param string $svg_data_uri SVG data URI.
86 * @return void
87 */
88 public static function register_toplevel_menu_slug_svg_icon( $menu_slug, $svg_data_uri ) {
89 $menu_slug = (string) $menu_slug;
90 $svg_data_uri = trim( (string) $svg_data_uri );
91
92 if ( '' === $menu_slug || '' === $svg_data_uri ) {
93 return;
94 }
95
96 if ( ! self::is_svg_data_uri( $svg_data_uri ) ) {
97 return;
98 }
99
100 self::$toplevel_menu_slug_svgs[ $menu_slug ] = $svg_data_uri;
101 }
102
103 /**
104 * Register an SVG icon for a menu entry by matching a substring within the anchor href.
105 *
106 * @since 7.6.0
107 *
108 * @param string $needle Substring expected in href.
109 * @param string $svg_data_uri SVG data URI.
110 * @return void
111 */
112 public static function register_menu_href_contains_svg_icon( $needle, $svg_data_uri ) {
113 $needle = trim( (string) $needle );
114 $svg_data_uri = trim( (string) $svg_data_uri );
115
116 if ( '' === $needle || '' === $svg_data_uri ) {
117 return;
118 }
119
120 if ( ! self::is_svg_data_uri( $svg_data_uri ) ) {
121 return;
122 }
123
124 self::$href_contains_svgs[ $needle ] = $svg_data_uri;
125 }
126
127 /**
128 * Enqueue inline CSS masks for all registered menu SVG icons.
129 *
130 * @since 7.6.0
131 *
132 * @return void
133 */
134 public static function enqueue_mask_css() {
135 if ( empty( self::$post_type_svgs ) && empty( self::$toplevel_menu_slug_svgs ) && empty( self::$href_contains_svgs ) ) {
136 return;
137 }
138
139 $css = '';
140
141 foreach ( self::$post_type_svgs as $post_type => $svg_data_uri ) {
142 $post_type = sanitize_key( (string) $post_type );
143 $svg_data_uri = trim( (string) $svg_data_uri );
144
145 if ( '' === $post_type || '' === $svg_data_uri || ! self::is_svg_data_uri( $svg_data_uri ) ) {
146 continue;
147 }
148
149 $selector = '#adminmenu .menu-icon-' . $post_type . ' .wp-menu-image:before';
150 $css .= self::build_mask_rule( $selector, $svg_data_uri );
151 }
152
153 foreach ( self::$toplevel_menu_slug_svgs as $menu_slug => $svg_data_uri ) {
154 $menu_slug = (string) $menu_slug;
155 $svg_data_uri = trim( (string) $svg_data_uri );
156
157 if ( '' === $menu_slug || '' === $svg_data_uri || ! self::is_svg_data_uri( $svg_data_uri ) ) {
158 continue;
159 }
160
161 $selectors = array(
162 '#toplevel_page_' . sanitize_title( $menu_slug ) . ' .wp-menu-image:before',
163 '#adminmenu a[href*="' . self::escape_css_attr_value( $menu_slug ) . '"] .wp-menu-image:before',
164 );
165 $css .= self::build_mask_rule( implode( ',' . PHP_EOL, $selectors ), $svg_data_uri );
166 }
167
168 foreach ( self::$href_contains_svgs as $needle => $svg_data_uri ) {
169 $needle = trim( (string) $needle );
170 $svg_data_uri = trim( (string) $svg_data_uri );
171
172 if ( '' === $needle || '' === $svg_data_uri || ! self::is_svg_data_uri( $svg_data_uri ) ) {
173 continue;
174 }
175
176 $selector = '#adminmenu a[href*="' . self::escape_css_attr_value( $needle ) . '"] .wp-menu-image:before';
177 $css .= self::build_mask_rule( $selector, $svg_data_uri );
178 }
179
180 if ( '' === $css ) {
181 return;
182 }
183
184 wp_add_inline_style( 'asenha-wp-admin', $css );
185 }
186
187 /**
188 * Build a CSS rule that masks a WP admin menu icon pseudo-element.
189 *
190 * @since 7.6.0
191 *
192 * @param string $selector CSS selector(s).
193 * @param string $svg_data_uri SVG data URI.
194 * @return string
195 */
196 private static function build_mask_rule( $selector, $svg_data_uri ) {
197 $selector = trim( (string) $selector );
198 $svg_data_uri = trim( (string) $svg_data_uri );
199
200 if ( '' === $selector || '' === $svg_data_uri ) {
201 return '';
202 }
203
204 return $selector . '{' . PHP_EOL .
205 "\tcontent:\"\";" . PHP_EOL .
206 "\tbackground-color:currentColor;" . PHP_EOL .
207 "\t-webkit-mask-image:url(\"" . $svg_data_uri . "\");" . PHP_EOL .
208 "\tmask-image:url(\"" . $svg_data_uri . "\");" . PHP_EOL .
209 "\t-webkit-mask-repeat:no-repeat;" . PHP_EOL .
210 "\tmask-repeat:no-repeat;" . PHP_EOL .
211 "\t-webkit-mask-position:center;" . PHP_EOL .
212 "\tmask-position:center;" . PHP_EOL .
213 "\t-webkit-mask-size:20px 20px;" . PHP_EOL .
214 "\tmask-size:20px 20px;" . PHP_EOL .
215 '}' . PHP_EOL;
216 }
217
218 /**
219 * Escape a value used inside a double-quoted CSS attribute selector.
220 *
221 * @since 7.6.0
222 *
223 * @param string $value Raw value.
224 * @return string
225 */
226 private static function escape_css_attr_value( $value ) {
227 return str_replace(
228 array( '\\', '"' ),
229 array( '\\\\', '\"' ),
230 (string) $value
231 );
232 }
233 }
234
235
236