[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Dec 21 08:20:01 2024 | Cross-referenced by PHPXref |