initial
This commit is contained in:
+235
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
/**
|
||||
* Shared helper for rendering SVG admin menu icons with correct colors on first paint.
|
||||
*
|
||||
* WordPress renders `menu_icon` SVG data URIs as <img> initially, and then core's
|
||||
* `svg-painter` inlines/recolors them, causing a visible "black → scheme color" flash.
|
||||
* This helper pre-empts that by forcing WordPress to use the `.wp-menu-image:before`
|
||||
* pseudo-element (via a Dashicon placeholder) and then applying the SVG as a CSS mask.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*/
|
||||
|
||||
namespace ASENHA\Classes;
|
||||
|
||||
class Admin_Menu_Svg_Icon_Mask {
|
||||
|
||||
/**
|
||||
* Registered SVG data URIs keyed by post type key.
|
||||
*
|
||||
* @since 7.6.0
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private static $post_type_svgs = array();
|
||||
|
||||
/**
|
||||
* Registered SVG data URIs keyed by top-level menu slug (from add_menu_page()).
|
||||
*
|
||||
* @since 7.6.0
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private static $toplevel_menu_slug_svgs = array();
|
||||
|
||||
/**
|
||||
* Registered SVG data URIs keyed by a substring to match against `href`.
|
||||
*
|
||||
* This is useful for menu slugs that are full URLs/queries (e.g. `post.php?post=123&action=edit`).
|
||||
*
|
||||
* @since 7.6.0
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private static $href_contains_svgs = array();
|
||||
|
||||
/**
|
||||
* Check whether a string is an SVG data URI that WordPress would render as an <img>.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @param mixed $value Potential menu icon.
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_svg_data_uri( $value ) {
|
||||
return is_string( $value ) && ( 0 === strpos( $value, 'data:image/svg+xml' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an SVG icon for a post type's admin menu entry.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @param string $post_type Post type key.
|
||||
* @param string $svg_data_uri SVG data URI.
|
||||
* @return void
|
||||
*/
|
||||
public static function register_post_type_svg_icon( $post_type, $svg_data_uri ) {
|
||||
$post_type = sanitize_key( (string) $post_type );
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $post_type || '' === $svg_data_uri ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! self::is_svg_data_uri( $svg_data_uri ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$post_type_svgs[ $post_type ] = $svg_data_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an SVG icon for a top-level menu entry created by add_menu_page().
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @param string $menu_slug Menu slug passed to add_menu_page().
|
||||
* @param string $svg_data_uri SVG data URI.
|
||||
* @return void
|
||||
*/
|
||||
public static function register_toplevel_menu_slug_svg_icon( $menu_slug, $svg_data_uri ) {
|
||||
$menu_slug = (string) $menu_slug;
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $menu_slug || '' === $svg_data_uri ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! self::is_svg_data_uri( $svg_data_uri ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$toplevel_menu_slug_svgs[ $menu_slug ] = $svg_data_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an SVG icon for a menu entry by matching a substring within the anchor href.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @param string $needle Substring expected in href.
|
||||
* @param string $svg_data_uri SVG data URI.
|
||||
* @return void
|
||||
*/
|
||||
public static function register_menu_href_contains_svg_icon( $needle, $svg_data_uri ) {
|
||||
$needle = trim( (string) $needle );
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $needle || '' === $svg_data_uri ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! self::is_svg_data_uri( $svg_data_uri ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$href_contains_svgs[ $needle ] = $svg_data_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue inline CSS masks for all registered menu SVG icons.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function enqueue_mask_css() {
|
||||
if ( empty( self::$post_type_svgs ) && empty( self::$toplevel_menu_slug_svgs ) && empty( self::$href_contains_svgs ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$css = '';
|
||||
|
||||
foreach ( self::$post_type_svgs as $post_type => $svg_data_uri ) {
|
||||
$post_type = sanitize_key( (string) $post_type );
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $post_type || '' === $svg_data_uri || ! self::is_svg_data_uri( $svg_data_uri ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$selector = '#adminmenu .menu-icon-' . $post_type . ' .wp-menu-image:before';
|
||||
$css .= self::build_mask_rule( $selector, $svg_data_uri );
|
||||
}
|
||||
|
||||
foreach ( self::$toplevel_menu_slug_svgs as $menu_slug => $svg_data_uri ) {
|
||||
$menu_slug = (string) $menu_slug;
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $menu_slug || '' === $svg_data_uri || ! self::is_svg_data_uri( $svg_data_uri ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$selectors = array(
|
||||
'#toplevel_page_' . sanitize_title( $menu_slug ) . ' .wp-menu-image:before',
|
||||
'#adminmenu a[href*="' . self::escape_css_attr_value( $menu_slug ) . '"] .wp-menu-image:before',
|
||||
);
|
||||
$css .= self::build_mask_rule( implode( ',' . PHP_EOL, $selectors ), $svg_data_uri );
|
||||
}
|
||||
|
||||
foreach ( self::$href_contains_svgs as $needle => $svg_data_uri ) {
|
||||
$needle = trim( (string) $needle );
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $needle || '' === $svg_data_uri || ! self::is_svg_data_uri( $svg_data_uri ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$selector = '#adminmenu a[href*="' . self::escape_css_attr_value( $needle ) . '"] .wp-menu-image:before';
|
||||
$css .= self::build_mask_rule( $selector, $svg_data_uri );
|
||||
}
|
||||
|
||||
if ( '' === $css ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_add_inline_style( 'asenha-wp-admin', $css );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a CSS rule that masks a WP admin menu icon pseudo-element.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @param string $selector CSS selector(s).
|
||||
* @param string $svg_data_uri SVG data URI.
|
||||
* @return string
|
||||
*/
|
||||
private static function build_mask_rule( $selector, $svg_data_uri ) {
|
||||
$selector = trim( (string) $selector );
|
||||
$svg_data_uri = trim( (string) $svg_data_uri );
|
||||
|
||||
if ( '' === $selector || '' === $svg_data_uri ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $selector . '{' . PHP_EOL .
|
||||
"\tcontent:\"\";" . PHP_EOL .
|
||||
"\tbackground-color:currentColor;" . PHP_EOL .
|
||||
"\t-webkit-mask-image:url(\"" . $svg_data_uri . "\");" . PHP_EOL .
|
||||
"\tmask-image:url(\"" . $svg_data_uri . "\");" . PHP_EOL .
|
||||
"\t-webkit-mask-repeat:no-repeat;" . PHP_EOL .
|
||||
"\tmask-repeat:no-repeat;" . PHP_EOL .
|
||||
"\t-webkit-mask-position:center;" . PHP_EOL .
|
||||
"\tmask-position:center;" . PHP_EOL .
|
||||
"\t-webkit-mask-size:20px 20px;" . PHP_EOL .
|
||||
"\tmask-size:20px 20px;" . PHP_EOL .
|
||||
'}' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a value used inside a double-quoted CSS attribute selector.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*
|
||||
* @param string $value Raw value.
|
||||
* @return string
|
||||
*/
|
||||
private static function escape_css_attr_value( $value ) {
|
||||
return str_replace(
|
||||
array( '\\', '"' ),
|
||||
array( '\\\\', '\"' ),
|
||||
(string) $value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user