[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-icons-registry.php (source)

   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  }


Generated : Sun Jun 14 08:20:09 2026 Cross-referenced by PHPXref