| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Icons API: WP_Icons_Registry class 5 * 6 * @package WordPress 7 * @since 7.0.0 8 */ 9 10 /** 11 * Core class used for interacting with registered icons. 12 * 13 * @since 7.0.0 14 */ 15 class WP_Icons_Registry { 16 /** 17 * Registered icons array. 18 * 19 * @since 7.0.0 20 * @var array[] 21 */ 22 protected $registered_icons = array(); 23 24 /** 25 * Container for the main instance of the class. 26 * 27 * @since 7.0.0 28 * @var WP_Icons_Registry|null 29 */ 30 protected static $instance = null; 31 32 /** 33 * Constructor. 34 * 35 * WP_Icons_Registry is a singleton class, so keep this protected. 36 * 37 * For 7.0, the Icons Registry is closed for third-party icon registry, 38 * serving only a subset of core icons. 39 * 40 * These icons are defined in @wordpress/packages (Gutenberg repository) as 41 * SVG files and as entries in a single manifest file. On init, the 42 * registry is loaded with those icons listed in the manifest. 43 * 44 * @since 7.0.0 45 */ 46 protected function __construct() { 47 $icons_directory = __DIR__ . '/images/icon-library/'; 48 $manifest_path = __DIR__ . '/assets/icon-library-manifest.php'; 49 50 if ( ! is_readable( $manifest_path ) ) { 51 wp_trigger_error( 52 __METHOD__, 53 __( 'Core icon collection manifest is missing or unreadable.' ) 54 ); 55 return; 56 } 57 58 $collection = include $manifest_path; 59 60 if ( empty( $collection ) ) { 61 wp_trigger_error( 62 __METHOD__, 63 __( 'Core icon collection manifest is empty or invalid.' ) 64 ); 65 return; 66 } 67 68 foreach ( $collection as $icon_name => $icon_data ) { 69 if ( 70 empty( $icon_data['filePath'] ) 71 || ! is_string( $icon_data['filePath'] ) 72 ) { 73 _doing_it_wrong( 74 __METHOD__, 75 __( 'Core icon collection manifest must provide valid a "filePath" for each icon.' ), 76 '7.0.0' 77 ); 78 return; 79 } 80 81 $this->register( 82 'core/' . $icon_name, 83 array( 84 'label' => $icon_data['label'], 85 'filePath' => $icons_directory . $icon_data['filePath'], 86 ) 87 ); 88 } 89 } 90 91 /** 92 * Registers an icon. 93 * 94 * @since 7.0.0 95 * 96 * @param string $icon_name Icon name including namespace. 97 * @param array $icon_properties { 98 * List of properties for the icon. 99 * 100 * @type string $label Required. A human-readable label for the icon. 101 * @type string $content Optional. SVG markup for the icon. 102 * If not provided, the content will be retrieved from the `filePath` if set. 103 * If both `content` and `filePath` are not set, the icon will not be registered. 104 * @type string $filePath Optional. The full path to the file containing the icon content. 105 * } 106 * @return bool True if the icon was registered with success and false otherwise. 107 */ 108 protected function register( $icon_name, $icon_properties ) { 109 if ( ! isset( $icon_name ) || ! is_string( $icon_name ) ) { 110 _doing_it_wrong( 111 __METHOD__, 112 __( 'Icon name must be a string.' ), 113 '7.0.0' 114 ); 115 return false; 116 } 117 118 $allowed_keys = array_fill_keys( array( 'label', 'content', 'filePath' ), 1 ); 119 foreach ( array_keys( $icon_properties ) as $key ) { 120 if ( ! array_key_exists( $key, $allowed_keys ) ) { 121 _doing_it_wrong( 122 __METHOD__, 123 sprintf( 124 // translators: %s is the name of any user-provided key 125 __( 'Invalid icon property: "%s".' ), 126 $key 127 ), 128 '7.0.0' 129 ); 130 return false; 131 } 132 } 133 134 if ( ! isset( $icon_properties['label'] ) || ! is_string( $icon_properties['label'] ) ) { 135 _doing_it_wrong( 136 __METHOD__, 137 __( 'Icon label must be a string.' ), 138 '7.0.0' 139 ); 140 return false; 141 } 142 143 if ( 144 ( ! isset( $icon_properties['content'] ) && ! isset( $icon_properties['filePath'] ) ) || 145 ( isset( $icon_properties['content'] ) && isset( $icon_properties['filePath'] ) ) 146 ) { 147 _doing_it_wrong( 148 __METHOD__, 149 __( 'Icons must provide either `content` or `filePath`.' ), 150 '7.0.0' 151 ); 152 return false; 153 } 154 155 if ( isset( $icon_properties['content'] ) ) { 156 if ( ! is_string( $icon_properties['content'] ) ) { 157 _doing_it_wrong( 158 __METHOD__, 159 __( 'Icon content must be a string.' ), 160 '7.0.0' 161 ); 162 return false; 163 } 164 165 $sanitized_icon_content = $this->sanitize_icon_content( $icon_properties['content'] ); 166 if ( empty( $sanitized_icon_content ) ) { 167 _doing_it_wrong( 168 __METHOD__, 169 __( 'Icon content does not contain valid SVG markup.' ), 170 '7.0.0' 171 ); 172 return false; 173 } 174 } 175 176 $icon = array_merge( 177 $icon_properties, 178 array( 'name' => $icon_name ) 179 ); 180 181 $this->registered_icons[ $icon_name ] = $icon; 182 183 return true; 184 } 185 186 /** 187 * Sanitizes the icon SVG content. 188 * 189 * Logic borrowed from twentytwenty. 190 * @see twentytwenty_get_theme_svg 191 * 192 * @since 7.0.0 193 * 194 * @param string $icon_content The icon SVG content to sanitize. 195 * @return string The sanitized icon SVG content. 196 */ 197 protected function sanitize_icon_content( $icon_content ) { 198 $allowed_tags = array( 199 'svg' => array( 200 'class' => true, 201 'xmlns' => true, 202 'width' => true, 203 'height' => true, 204 'viewbox' => true, 205 'aria-hidden' => true, 206 'role' => true, 207 'focusable' => true, 208 ), 209 'path' => array( 210 'fill' => true, 211 'fill-rule' => true, 212 'd' => true, 213 'transform' => true, 214 ), 215 'polygon' => array( 216 'fill' => true, 217 'fill-rule' => true, 218 'points' => true, 219 'transform' => true, 220 'focusable' => true, 221 ), 222 ); 223 return wp_kses( $icon_content, $allowed_tags ); 224 } 225 226 /** 227 * Retrieves the content of a registered icon. 228 * 229 * @since 7.0.0 230 * 231 * @param string $icon_name Icon name including namespace. 232 * @return string|null The content of the icon, if found. 233 */ 234 protected function get_content( $icon_name ) { 235 if ( ! isset( $this->registered_icons[ $icon_name ]['content'] ) ) { 236 $content = file_get_contents( 237 $this->registered_icons[ $icon_name ]['filePath'] 238 ); 239 $content = $this->sanitize_icon_content( $content ); 240 241 if ( empty( $content ) ) { 242 wp_trigger_error( 243 __METHOD__, 244 __( 'Icon content does not contain valid SVG markup.' ) 245 ); 246 return null; 247 } 248 249 $this->registered_icons[ $icon_name ]['content'] = $content; 250 } 251 return $this->registered_icons[ $icon_name ]['content']; 252 } 253 254 /** 255 * Retrieves an array containing the properties of a registered icon. 256 * 257 * @since 7.0.0 258 * 259 * @param string $icon_name Icon name including namespace. 260 * @return array|null Registered icon properties or `null` if the icon is not registered. 261 */ 262 public function get_registered_icon( $icon_name ) { 263 if ( ! $this->is_registered( $icon_name ) ) { 264 return null; 265 } 266 267 $icon = $this->registered_icons[ $icon_name ]; 268 $icon['content'] = $icon['content'] ?? $this->get_content( $icon_name ); 269 270 return $icon; 271 } 272 273 /** 274 * Retrieves all registered icons. 275 * 276 * @since 7.0.0 277 * 278 * @param string $search Optional. Search term by which to filter the icons. 279 * @return array[] Array of arrays containing the registered icon properties. 280 */ 281 public function get_registered_icons( $search = '' ) { 282 $icons = array(); 283 284 foreach ( $this->registered_icons as $icon ) { 285 if ( ! empty( $search ) && false === stripos( $icon['name'], $search ) ) { 286 continue; 287 } 288 289 $icon['content'] = $icon['content'] ?? $this->get_content( $icon['name'] ); 290 $icons[] = $icon; 291 } 292 293 return $icons; 294 } 295 296 /** 297 * Checks if an icon is registered. 298 * 299 * @since 7.0.0 300 * 301 * @param string $icon_name Icon name including namespace. 302 * @return bool True if the icon is registered, false otherwise. 303 */ 304 public function is_registered( $icon_name ) { 305 return isset( $this->registered_icons[ $icon_name ] ); 306 } 307 308 /** 309 * Utility method to retrieve the main instance of the class. 310 * 311 * The instance will be created if it does not exist yet. 312 * 313 * @since 7.0.0 314 * 315 * @return WP_Icons_Registry The main instance. 316 */ 317 public static function get_instance() { 318 if ( null === self::$instance ) { 319 self::$instance = new self(); 320 } 321 322 return self::$instance; 323 } 324 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Jun 14 08:20:09 2026 | Cross-referenced by PHPXref |