Skip to content

Commit

Permalink
Moves validation from providers to Validator.
Browse files Browse the repository at this point in the history
Moves all of the validation logic from the providers
to the Validator.

Adds tests.
  • Loading branch information
hellofromtonya committed Oct 15, 2021
1 parent 1d02ed4 commit 91d18ad
Show file tree
Hide file tree
Showing 11 changed files with 1,823 additions and 648 deletions.
35 changes: 16 additions & 19 deletions src/wp-includes/webfonts-api/class-wp-webfonts-registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function get_by_provider( $provider_id ) {
* @since 5.9.0
*
* @param string $font_family Family font to fetch.
* @return string[][] Registered webfonts.
* @return array[] Registered webfonts.
*/
public function get_by_font_family( $font_family ) {
if ( ! is_string( $font_family ) || '' === $font_family ) {
Expand Down Expand Up @@ -116,17 +116,19 @@ public function get_by_font_family( $font_family ) {
*
* @since 5.9.0
*
* @param string[] $webfont Webfont definition.
* @param array $webfont Webfont definition.
* @return string Registration key.
*/
public function register( array $webfont ) {
$webfont = $this->merge_optional_parameters( $webfont );
$webfont = $this->convert_to_kabeb_case( $webfont );

// Validate schema.
if ( ! $this->is_schema_valid( $webfont ) ) {
if ( ! $this->validator->is_valid_schema( $webfont ) ) {
return '';
}

$webfont = $this->validator->set_valid_properties( $webfont );

// Add to registry.
$registration_key = $this->generate_registration_key( $webfont );
if ( ! isset( $this->registry[ $registration_key ] ) ) {
Expand All @@ -138,29 +140,24 @@ public function register( array $webfont ) {
}

/**
* Merge optional parameters into webfont definition.
* Convert camelCase parameters into kabeb_case.
*
* @since 5.9.0
*
* @param string[] $webfont Webfont definition.
* @return string[] Webfont with optional parameters.
* @return array Webfont with kabeb_case parameters (keys).
*/
private function merge_optional_parameters( array $webfont ) {
if ( ! isset( $webfont['fontStyle'] ) ) {
$webfont['fontStyle'] = 'normal';
}

if ( ! isset( $webfont['fontWeight'] ) ) {
$webfont['fontWeight'] = '400';
}
private function convert_to_kabeb_case( array $webfont ) {
$kebab_case = preg_replace( '/(?<!^)[A-Z]/', '-$0', array_keys( $webfont ) );
$kebab_case = array_map( 'strtolower', $kebab_case );

return $webfont;
return array_combine( $kebab_case, array_values( $webfont ) );
}

/**
* Generates the registration key.
*
* Format: fontFamily.fontStyle.fontWeight
* Format: font-family.font-style.font-weight
* For example: `'open-sans.normal.400'`.
*
* @since 5.9.0
Expand All @@ -171,9 +168,9 @@ private function merge_optional_parameters( array $webfont ) {
private function generate_registration_key( array $webfont ) {
return sprintf(
'%s.%s.%s',
$this->convert_font_family_into_key( $webfont['fontFamily'] ),
trim( $webfont['fontStyle'] ),
trim( $webfont['fontWeight'] )
$this->convert_font_family_into_key( $webfont['font-family'] ),
trim( $webfont['font-style'] ),
trim( $webfont['font-weight'] )
);
}

Expand Down
220 changes: 156 additions & 64 deletions src/wp-includes/webfonts-api/class-wp-webfonts-schema-validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,58 +21,104 @@ class WP_Webfonts_Schema_Validator {
*
* @var string[]
*/
private $valid_font_style = array(
'normal',
'italic',
'oblique',
// Global values.
'inherit',
'initial',
'revert',
'unset',
protected $font_style = array( 'normal', 'italic', 'oblique', 'inherit', 'initial', 'revert', 'unset' );

/**
* Valid font weight values.
*
* @since 5.9.0
*
* @var string[]
*/
protected $font_weight = array( 'normal', 'bold', 'bolder', 'lighter', 'inherit' );

/**
* Valid font display values.
*
* @since 5.9.0
*
* @var string[]
*/
protected $font_display = array( 'auto', 'block', 'swap', 'fallback' );

/**
* An array of valid CSS properties for @font-face.
*
* @since 5.9.0
*
* @var string[]
*/
protected $font_face_properties = array(
'ascend-override',
'descend-override',
'font-display',
'font-family',
'font-stretch',
'font-style',
'font-weight',
'font-variant',
'font-feature-settings',
'font-variation-settings',
'line-gap-override',
'size-adjust',
'src',
'unicode-range',
);

/**
* Basic schema structure.
*
* @since 5.9.0
*
* @var array
*/
protected $basic_schema = array(
'provider' => '',
'font-family' => '',
'font-style' => 'normal',
'font-weight' => '400',
'font-display' => 'fallback',
);

/**
* Webfont being validated.
*
* @var string[]
* Set as a property for performance.
*
* @var array
*/
private $webfont = array();

/**
* Checks if the given webfont schema is validate.
* Checks if the given webfont schema is valid.
*
* @since 5.9.0
*
* @param string[] $webfont Webfont definition.
* @param array $webfont Webfont to validate.
* @return bool True when valid. False when invalid.
*/
public function is_schema_valid( array $webfont ) {
$this->webfont = $webfont;

$is_valid = (
$this->is_provider_valid() &&
$this->is_font_family_valid() &&
$this->is_font_style_valid() &&
$this->is_font_weight_valid()
public function is_valid_schema( array $webfont ) {
return (
$this->is_valid_provider( $webfont ) &&
$this->is_valid_font_family( $webfont )
);

$this->webfont = array();

return $is_valid;
}

/**
* Checks if the provider is validate.
*
* @since 5.9.0
*
* @param array $webfont Webfont to valiate.
* @return bool True if valid. False if invalid.
*/
private function is_provider_valid() {
private function is_valid_provider( array $webfont ) {
// @todo check if provider is registered.

if ( empty( $this->webfont['provider'] ) || ! is_string( $this->webfont['provider'] ) ) {
if (
empty( $webfont['provider'] ) ||
! is_string( $webfont['provider'] )
) {
trigger_error( __( 'Webfont provider must be a non-empty string.' ) );

return false;
Expand All @@ -86,10 +132,14 @@ private function is_provider_valid() {
*
* @since 5.9.0
*
* @param array $webfont Webfont to validate.
* @return bool True if valid. False if invalid.
*/
private function is_font_family_valid() {
if ( empty( $this->webfont['fontFamily'] ) || ! is_string( $this->webfont['fontFamily'] ) ) {
private function is_valid_font_family( array $webfont ) {
if (
empty( $webfont['font-family'] ) ||
! is_string( $webfont['font-family'] )
) {
trigger_error( __( 'Webfont font family must be a non-empty string.' ) );

return false;
Expand All @@ -99,67 +149,109 @@ private function is_font_family_valid() {
}

/**
* Checks if the font style is validate.
* Sets valid properties.
*
* @since 5.9.0
*
* @return bool True if valid. False if invalid.
* @param array $webfont Webfont definition.
* @return array Updated webfont.
*/
private function is_font_style_valid() {
if ( empty( $this->webfont['fontStyle'] ) || ! is_string( $this->webfont['fontStyle'] ) ) {
trigger_error( __( 'Webfont font style must be a non-empty string.' ) );
return false;
}
public function set_valid_properties( array $webfont ) {
$this->webfont = array_merge( $this->basic_schema, $webfont );

if ( ! $this->is_font_style_value_valid( $this->webfont['fontStyle'] ) ) {
trigger_error(
sprintf(
/* translators: 1: Slant angle, 2: Given font style. */
__( 'Webfont font style must be normal, italic, oblique, or oblique %1$s. Given: %2$s.' ),
'<angle>',
$this->webfont['fontStyle']
)
);
$this->set_valid_font_face_property();
$this->set_valid_font_style();
$this->set_valid_font_weight();
$this->set_valid_font_display();

return false;
}
$webfont = $this->webfont;
$this->webfont = array(); // Reset property.

return true;
return $webfont;
}

/**
* Checks if the given font-style is valid.
* Checks if the CSS property is valid for @font-face.
*
* @since 5.9.0
*
* @param string $font_style Font style to validate.
* @return bool True when font-style is valid.
*/
private function is_font_style_value_valid( $font_style ) {
if ( in_array( $font_style, $this->valid_font_style, true ) ) {
return true;
private function set_valid_font_face_property() {
foreach ( array_keys( $this->webfont ) as $property ) {
/*
* Skip valid configuration parameters (these are configuring the webfont
* but are not @font-face properties.
*/
if ( 'provider' === $property ) {
continue;
}

if ( ! in_array( $property, $this->font_face_properties, true ) ) {
unset( $this->webfont[ $property ] );
}
}
}

// @todo Check for oblique <angle>.
/**
* Checks if the font style is validate.
*
* @since 5.9.0
*/
private function set_valid_font_style() {
// If empty or not a string, trigger an error and then set the default value.
if (
empty( $this->webfont['font-style'] ) ||
! is_string( $this->webfont['font-style'] )
) {
trigger_error( __( 'Webfont font style must be a non-empty string.' ) );

} elseif ( // Bail out if the font-weight is a valid value.
in_array( $this->webfont['font-style'], $this->font_style, true ) ||
preg_match( '/^oblique\s+(\d+)%/', $this->webfont['font-style'] )
) {
return;
}

return false;
$this->webfont['font-style'] = 'normal';
}

/**
* Checks if the font weight is validate.
* Sets a default font weight if invalid.
*
* @since 5.9.0
*
* @return bool True if valid. False if invalid.
*/
private function is_font_weight_valid() {
// @todo validate the value.
if ( empty( $this->webfont['fontWeight'] ) || ! is_string( $this->webfont['fontWeight'] ) ) {
private function set_valid_font_weight() {
// If empty or not a string, trigger an error and then set the default value.
if (
empty( $this->webfont['font-weight'] ) ||
! is_string( $this->webfont['font-weight'] )
) {
trigger_error( __( 'Webfont font weight must be a non-empty string.' ) );

return false;
} elseif ( // Bail out if the font-weight is a valid value.
in_array( $this->webfont['font-weight'], $this->font_weight, true ) ||
preg_match( '/^(\d+)$/', $this->webfont['font-weight'], $matches ) ||
preg_match( '/^(\d+)\s+(\d+)$/', $this->webfont['font-weight'], $matches )
) {
return;
}

return true;
// Not valid. Set the default value.
$this->webfont['font-weight'] = '400';
}

/**
* Sets a default font display if invalid.
*
* @since 5.9.0
*/
private function set_valid_font_display() {
if (
! empty( $this->webfont['font-display'] ) &&
in_array( $this->webfont['font-display'], $this->font_display, true )
) {
return;
}

$this->webfont['font-display'] = 'fallback';
}
}
Loading

0 comments on commit 91d18ad

Please sign in to comment.