File "class-wp-font-collection.php"

Full Path: /home/pumpbmko/public_html/wp-content/plugins/gutenberg/lib/compat/wordpress-6.5/fonts/class-wp-font-collection.php
File size: 9.04 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * Font Collection class.
 *
 * This file contains the Font Collection class definition.
 *
 * @package    WordPress
 * @subpackage Font Library
 * @since      6.5.0
 */

if ( ! class_exists( 'WP_Font_Collection' ) ) {

	/**
	 * Font Collection class.
	 *
	 * @since 6.5.0
	 *
	 * @see wp_register_font_collection()
	 */
	final class WP_Font_Collection {
		/**
		 * The unique slug for the font collection.
		 *
		 * @since 6.5.0
		 * @var string
		 */
		public $slug;

		/**
		 * Font collection data.
		 *
		 * @since 6.5.0
		 * @var array|WP_Error|null
		 */
		private $data;

		/**
		 * Font collection JSON file path or URL.
		 *
		 * @since 6.5.0
		 * @var string|null
		 */
		private $src;

		/**
		 * WP_Font_Collection constructor.
		 *
		 * @since 6.5.0
		 *
		 * @param string $slug Font collection slug. May only contain alphanumeric characters, dashes,
		 *                     and underscores. See sanitize_title().
		 * @param array  $args Font collection data. See wp_register_font_collection() for information on accepted arguments.
		 */
		public function __construct( string $slug, array $args ) {
			$this->slug = sanitize_title( $slug );
			if ( $this->slug !== $slug ) {
				_doing_it_wrong(
					__METHOD__,
					/* translators: %s: Font collection slug. */
					sprintf( __( 'Font collection slug "%s" is not valid. Slugs must use only alphanumeric characters, dashes, and underscores.', 'gutenberg' ), $slug ),
					'6.5.0'
				);
			}

			$required_properties = array( 'name', 'font_families' );

			if ( isset( $args['font_families'] ) && is_string( $args['font_families'] ) ) {
				// JSON data is lazy loaded by ::get_data().
				$this->src = $args['font_families'];
				unset( $args['font_families'] );

				$required_properties = array( 'name' );
			}

			$this->data = $this->sanitize_and_validate_data( $args, $required_properties );
		}

		/**
		 * Retrieves the font collection data.
		 *
		 * @since 6.5.0
		 *
		 * @return array|WP_Error An array containing the font collection data, or a WP_Error on failure.
		 */
		public function get_data() {
			if ( is_wp_error( $this->data ) ) {
				return $this->data;
			}

			// If the collection uses JSON data, load it and cache the data/error.
			if ( isset( $this->src ) ) {
				$this->data = $this->load_from_json( $this->src );
			}

			if ( is_wp_error( $this->data ) ) {
				return $this->data;
			}

			// Set defaults for optional properties.
			$defaults = array(
				'description' => '',
				'categories'  => array(),
			);

			return wp_parse_args( $this->data, $defaults );
		}

		/**
		 * Loads font collection data from a JSON file or URL.
		 *
		 * @since 6.5.0
		 *
		 * @param string $file_or_url File path or URL to a JSON file containing the font collection data.
		 * @return array|WP_Error An array containing the font collection data on success,
		 *                        else an instance of WP_Error on failure.
		 */
		private function load_from_json( $file_or_url ) {
			$url  = wp_http_validate_url( $file_or_url );
			$file = file_exists( $file_or_url ) ? wp_normalize_path( realpath( $file_or_url ) ) : false;

			if ( ! $url && ! $file ) {
				// translators: %s: File path or URL to font collection JSON file.
				$message = __( 'Font collection JSON file is invalid or does not exist.', 'gutenberg' );
				_doing_it_wrong( __METHOD__, $message, '6.5.0' );
				return new WP_Error( 'font_collection_json_missing', $message );
			}

			$data = $url ? $this->load_from_url( $url ) : $this->load_from_file( $file );

			if ( is_wp_error( $data ) ) {
				return $data;
			}

			$data = array(
				'name'          => $this->data['name'],
				'font_families' => $data['font_families'],
			);

			if ( isset( $this->data['description'] ) ) {
				$data['description'] = $this->data['description'];
			}

			if ( isset( $this->data['categories'] ) ) {
				$data['categories'] = $this->data['categories'];
			}

			return $data;
		}

		/**
		 * Loads the font collection data from a JSON file path.
		 *
		 * @since 6.5.0
		 *
		 * @param string $file File path to a JSON file containing the font collection data.
		 * @return array|WP_Error An array containing the font collection data on success,
		 *                        else an instance of WP_Error on failure.
		 */
		private function load_from_file( $file ) {
			$data = wp_json_file_decode( $file, array( 'associative' => true ) );
			if ( empty( $data ) ) {
				return new WP_Error( 'font_collection_decode_error', __( 'Error decoding the font collection JSON file contents.', 'gutenberg' ) );
			}

			return $this->sanitize_and_validate_data( $data, array( 'font_families' ) );
		}

		/**
		 * Loads the font collection data from a JSON file URL.
		 *
		 * @since 6.5.0
		 *
		 * @param string $url URL to a JSON file containing the font collection data.
		 * @return array|WP_Error An array containing the font collection data on success,
		 *                        else an instance of WP_Error on failure.
		 */
		private function load_from_url( $url ) {
			// Limit key to 167 characters to avoid failure in the case of a long URL.
			$transient_key = substr( 'wp_font_collection_url_' . $url, 0, 167 );
			$data          = get_site_transient( $transient_key );

			if ( false === $data ) {
				$response = wp_safe_remote_get( $url );
				if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
					return new WP_Error(
						'font_collection_request_error',
						sprintf(
							// translators: %s: Font collection URL.
							__( 'Error fetching the font collection data from "%s".', 'gutenberg' ),
							$url
						)
					);
				}

				$data = json_decode( wp_remote_retrieve_body( $response ), true );
				if ( empty( $data ) ) {
					return new WP_Error( 'font_collection_decode_error', __( 'Error decoding the font collection data from the HTTP response JSON.', 'gutenberg' ) );
				}

				// Make sure the data is valid before storing it in a transient.
				$data = $this->sanitize_and_validate_data( $data, array( 'font_families' ) );
				if ( is_wp_error( $data ) ) {
					return $data;
				}

				set_site_transient( $transient_key, $data, DAY_IN_SECONDS );
			}

			return $data;
		}

		/**
		 * Sanitizes and validates the font collection data.
		 *
		 * @since 6.5.0
		 *
		 * @param array $data                Font collection data to sanitize and validate.
		 * @param array $required_properties Required properties that must exist in the passed data.
		 * @return array|WP_Error Sanitized data if valid, otherwise a WP_Error instance.
		 */
		private function sanitize_and_validate_data( $data, $required_properties = array() ) {
			$schema = self::get_sanitization_schema();
			$data   = WP_Font_Utils::sanitize_from_schema( $data, $schema );

			foreach ( $required_properties as $property ) {
				if ( empty( $data[ $property ] ) ) {
					$message = sprintf(
						// translators: 1: Font collection slug, 2: Missing property name, e.g. "font_families".
						__( 'Font collection "%1$s" has missing or empty property: "%2$s".', 'gutenberg' ),
						$this->slug,
						$property
					);
					_doing_it_wrong( __METHOD__, $message, '6.5.0' );
					return new WP_Error( 'font_collection_missing_property', $message );
				}
			}

			return $data;
		}

		/**
		 * Retrieves the font collection sanitization schema.
		 *
		 * @since 6.5.0
		 *
		 * @return array Font collection sanitization schema.
		 */
		private static function get_sanitization_schema() {
			return array(
				'name'          => 'sanitize_text_field',
				'description'   => 'sanitize_text_field',
				'font_families' => array(
					array(
						'font_family_settings' => array(
							'name'       => 'sanitize_text_field',
							'slug'       => static function ( $value ) {
								return _wp_to_kebab_case( sanitize_title( $value ) );
							},
							'fontFamily' => 'WP_Font_Utils::sanitize_font_family',
							'preview'    => 'sanitize_url',
							'fontFace'   => array(
								array(
									'fontFamily'          => 'sanitize_text_field',
									'fontStyle'           => 'sanitize_text_field',
									'fontWeight'          => 'sanitize_text_field',
									'src'                 => static function ( $value ) {
										return is_array( $value )
											? array_map( 'sanitize_text_field', $value )
											: sanitize_text_field( $value );
									},
									'preview'             => 'sanitize_url',
									'fontDisplay'         => 'sanitize_text_field',
									'fontStretch'         => 'sanitize_text_field',
									'ascentOverride'      => 'sanitize_text_field',
									'descentOverride'     => 'sanitize_text_field',
									'fontVariant'         => 'sanitize_text_field',
									'fontFeatureSettings' => 'sanitize_text_field',
									'fontVariationSettings' => 'sanitize_text_field',
									'lineGapOverride'     => 'sanitize_text_field',
									'sizeAdjust'          => 'sanitize_text_field',
									'unicodeRange'        => 'sanitize_text_field',
								),
							),
						),
						'categories'           => array( 'sanitize_title' ),
					),
				),
				'categories'    => array(
					array(
						'name' => 'sanitize_text_field',
						'slug' => 'sanitize_title',
					),
				),
			);
		}
	}
}