[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/fonts/ -> class-wp-font-collection.php (source)

   1  <?php
   2  /**
   3   * Font Collection class.
   4   *
   5   * This file contains the Font Collection class definition.
   6   *
   7   * @package    WordPress
   8   * @subpackage Fonts
   9   * @since      6.5.0
  10   */
  11  
  12  /**
  13   * Font Collection class.
  14   *
  15   * @since 6.5.0
  16   *
  17   * @see wp_register_font_collection()
  18   */
  19  final class WP_Font_Collection {
  20      /**
  21       * The unique slug for the font collection.
  22       *
  23       * @since 6.5.0
  24       * @var string
  25       */
  26      public $slug;
  27  
  28      /**
  29       * Font collection data.
  30       *
  31       * @since 6.5.0
  32       * @var array|WP_Error|null
  33       */
  34      private $data;
  35  
  36      /**
  37       * Font collection JSON file path or URL.
  38       *
  39       * @since 6.5.0
  40       * @var string|null
  41       */
  42      private $src;
  43  
  44      /**
  45       * WP_Font_Collection constructor.
  46       *
  47       * @since 6.5.0
  48       *
  49       * @param string $slug Font collection slug. May only contain alphanumeric characters, dashes,
  50       *                     and underscores. See sanitize_title().
  51       * @param array  $args Font collection data. See wp_register_font_collection() for information on accepted arguments.
  52       */
  53  	public function __construct( string $slug, array $args ) {
  54          $this->slug = sanitize_title( $slug );
  55          if ( $this->slug !== $slug ) {
  56              _doing_it_wrong(
  57                  __METHOD__,
  58                  /* translators: %s: Font collection slug. */
  59                  sprintf( __( 'Font collection slug "%s" is not valid. Slugs must use only alphanumeric characters, dashes, and underscores.' ), $slug ),
  60                  '6.5.0'
  61              );
  62          }
  63  
  64          $required_properties = array( 'name', 'font_families' );
  65  
  66          if ( isset( $args['font_families'] ) && is_string( $args['font_families'] ) ) {
  67              // JSON data is lazy loaded by ::get_data().
  68              $this->src = $args['font_families'];
  69              unset( $args['font_families'] );
  70  
  71              $required_properties = array( 'name' );
  72          }
  73  
  74          $this->data = $this->sanitize_and_validate_data( $args, $required_properties );
  75      }
  76  
  77      /**
  78       * Retrieves the font collection data.
  79       *
  80       * @since 6.5.0
  81       *
  82       * @return array|WP_Error An array containing the font collection data, or a WP_Error on failure.
  83       */
  84  	public function get_data() {
  85          if ( is_wp_error( $this->data ) ) {
  86              return $this->data;
  87          }
  88  
  89          // If the collection uses JSON data, load it and cache the data/error.
  90          if ( isset( $this->src ) ) {
  91              $this->data = $this->load_from_json( $this->src );
  92          }
  93  
  94          if ( is_wp_error( $this->data ) ) {
  95              return $this->data;
  96          }
  97  
  98          // Set defaults for optional properties.
  99          $defaults = array(
 100              'description' => '',
 101              'categories'  => array(),
 102          );
 103  
 104          return wp_parse_args( $this->data, $defaults );
 105      }
 106  
 107      /**
 108       * Loads font collection data from a JSON file or URL.
 109       *
 110       * @since 6.5.0
 111       *
 112       * @param string $file_or_url File path or URL to a JSON file containing the font collection data.
 113       * @return array|WP_Error An array containing the font collection data on success,
 114       *                        else an instance of WP_Error on failure.
 115       */
 116  	private function load_from_json( $file_or_url ) {
 117          $url  = wp_http_validate_url( $file_or_url );
 118          $file = file_exists( $file_or_url ) ? wp_normalize_path( realpath( $file_or_url ) ) : false;
 119  
 120          if ( ! $url && ! $file ) {
 121              // translators: %s: File path or URL to font collection JSON file.
 122              $message = __( 'Font collection JSON file is invalid or does not exist.' );
 123              _doing_it_wrong( __METHOD__, $message, '6.5.0' );
 124              return new WP_Error( 'font_collection_json_missing', $message );
 125          }
 126  
 127          $data = $url ? $this->load_from_url( $url ) : $this->load_from_file( $file );
 128  
 129          if ( is_wp_error( $data ) ) {
 130              return $data;
 131          }
 132  
 133          $data = array(
 134              'name'          => $this->data['name'],
 135              'font_families' => $data['font_families'],
 136          );
 137  
 138          if ( isset( $this->data['description'] ) ) {
 139              $data['description'] = $this->data['description'];
 140          }
 141  
 142          if ( isset( $this->data['categories'] ) ) {
 143              $data['categories'] = $this->data['categories'];
 144          }
 145  
 146          return $data;
 147      }
 148  
 149      /**
 150       * Loads the font collection data from a JSON file path.
 151       *
 152       * @since 6.5.0
 153       *
 154       * @param string $file File path to a JSON file containing the font collection data.
 155       * @return array|WP_Error An array containing the font collection data on success,
 156       *                        else an instance of WP_Error on failure.
 157       */
 158  	private function load_from_file( $file ) {
 159          $data = wp_json_file_decode( $file, array( 'associative' => true ) );
 160          if ( empty( $data ) ) {
 161              return new WP_Error( 'font_collection_decode_error', __( 'Error decoding the font collection JSON file contents.' ) );
 162          }
 163  
 164          return $this->sanitize_and_validate_data( $data, array( 'font_families' ) );
 165      }
 166  
 167      /**
 168       * Loads the font collection data from a JSON file URL.
 169       *
 170       * @since 6.5.0
 171       *
 172       * @param string $url URL to a JSON file containing the font collection data.
 173       * @return array|WP_Error An array containing the font collection data on success,
 174       *                        else an instance of WP_Error on failure.
 175       */
 176  	private function load_from_url( $url ) {
 177          // Limit key to 167 characters to avoid failure in the case of a long URL.
 178          $transient_key = substr( 'wp_font_collection_url_' . $url, 0, 167 );
 179          $data          = get_site_transient( $transient_key );
 180  
 181          if ( false === $data ) {
 182              $response = wp_safe_remote_get( $url );
 183              if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
 184                  return new WP_Error(
 185                      'font_collection_request_error',
 186                      sprintf(
 187                          // translators: %s: Font collection URL.
 188                          __( 'Error fetching the font collection data from "%s".' ),
 189                          $url
 190                      )
 191                  );
 192              }
 193  
 194              $data = json_decode( wp_remote_retrieve_body( $response ), true );
 195              if ( empty( $data ) ) {
 196                  return new WP_Error( 'font_collection_decode_error', __( 'Error decoding the font collection data from the HTTP response JSON.' ) );
 197              }
 198  
 199              // Make sure the data is valid before storing it in a transient.
 200              $data = $this->sanitize_and_validate_data( $data, array( 'font_families' ) );
 201              if ( is_wp_error( $data ) ) {
 202                  return $data;
 203              }
 204  
 205              set_site_transient( $transient_key, $data, DAY_IN_SECONDS );
 206          }
 207  
 208          return $data;
 209      }
 210  
 211      /**
 212       * Sanitizes and validates the font collection data.
 213       *
 214       * @since 6.5.0
 215       *
 216       * @param array $data                Font collection data to sanitize and validate.
 217       * @param array $required_properties Required properties that must exist in the passed data.
 218       * @return array|WP_Error Sanitized data if valid, otherwise a WP_Error instance.
 219       */
 220  	private function sanitize_and_validate_data( $data, $required_properties = array() ) {
 221          $schema = self::get_sanitization_schema();
 222          $data   = WP_Font_Utils::sanitize_from_schema( $data, $schema );
 223  
 224          foreach ( $required_properties as $property ) {
 225              if ( empty( $data[ $property ] ) ) {
 226                  $message = sprintf(
 227                      // translators: 1: Font collection slug, 2: Missing property name, e.g. "font_families".
 228                      __( 'Font collection "%1$s" has missing or empty property: "%2$s".' ),
 229                      $this->slug,
 230                      $property
 231                  );
 232                  _doing_it_wrong( __METHOD__, $message, '6.5.0' );
 233                  return new WP_Error( 'font_collection_missing_property', $message );
 234              }
 235          }
 236  
 237          return $data;
 238      }
 239  
 240      /**
 241       * Retrieves the font collection sanitization schema.
 242       *
 243       * @since 6.5.0
 244       *
 245       * @return array Font collection sanitization schema.
 246       */
 247  	private static function get_sanitization_schema() {
 248          return array(
 249              'name'          => 'sanitize_text_field',
 250              'description'   => 'sanitize_text_field',
 251              'font_families' => array(
 252                  array(
 253                      'font_family_settings' => array(
 254                          'name'       => 'sanitize_text_field',
 255                          'slug'       => static function ( $value ) {
 256                              return _wp_to_kebab_case( sanitize_title( $value ) );
 257                          },
 258                          'fontFamily' => 'WP_Font_Utils::sanitize_font_family',
 259                          'preview'    => 'sanitize_url',
 260                          'fontFace'   => array(
 261                              array(
 262                                  'fontFamily'            => 'sanitize_text_field',
 263                                  'fontStyle'             => 'sanitize_text_field',
 264                                  'fontWeight'            => 'sanitize_text_field',
 265                                  'src'                   => static function ( $value ) {
 266                                      return is_array( $value )
 267                                          ? array_map( 'sanitize_text_field', $value )
 268                                          : sanitize_text_field( $value );
 269                                  },
 270                                  'preview'               => 'sanitize_url',
 271                                  'fontDisplay'           => 'sanitize_text_field',
 272                                  'fontStretch'           => 'sanitize_text_field',
 273                                  'ascentOverride'        => 'sanitize_text_field',
 274                                  'descentOverride'       => 'sanitize_text_field',
 275                                  'fontVariant'           => 'sanitize_text_field',
 276                                  'fontFeatureSettings'   => 'sanitize_text_field',
 277                                  'fontVariationSettings' => 'sanitize_text_field',
 278                                  'lineGapOverride'       => 'sanitize_text_field',
 279                                  'sizeAdjust'            => 'sanitize_text_field',
 280                                  'unicodeRange'          => 'sanitize_text_field',
 281                              ),
 282                          ),
 283                      ),
 284                      'categories'           => array( 'sanitize_title' ),
 285                  ),
 286              ),
 287              'categories'    => array(
 288                  array(
 289                      'name' => 'sanitize_text_field',
 290                      'slug' => 'sanitize_title',
 291                  ),
 292              ),
 293          );
 294      }
 295  }


Generated : Sat Apr 27 08:20:02 2024 Cross-referenced by PHPXref