Title: WP_REST_Global_Styles_Controller::validate_custom_css
Published: March 29, 2023
Last modified: May 20, 2026

---

# WP_REST_Global_Styles_Controller::validate_custom_css( string $css ): true|󠀁[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)󠁿

## In this article

 * [Description](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#description)
    - [See also](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#see-also)
 * [Parameters](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#source)
 * [Related](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#changelog)

[ Back to top](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#wp--skip-link--target)

Validate style.css as valid CSS.

## 󠀁[Description](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#description)󠁿

Currently just checks that CSS will not break an HTML STYLE tag.

### 󠀁[See also](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#see-also)󠁿

 * [WP_Customize_Custom_CSS_Setting::validate()](https://developer.wordpress.org/reference/classes/WP_Customize_Custom_CSS_Setting/validate/)

## 󠀁[Parameters](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#parameters)󠁿

 `$css`stringrequired

CSS to validate.

## 󠀁[Return](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#return)󠁿

 true|[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/) True
if the input was validated, otherwise [WP_Error](https://developer.wordpress.org/reference/classes/wp_error/).

## 󠀁[Source](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#source)󠁿

    ```php
    protected function validate_custom_css( $css ) {
    	$length = strlen( $css );
    	for (
    		$at = strcspn( $css, '<' );
    		$at < $length;
    		$at += strcspn( $css, '<', ++$at )
    	) {
    		$remaining_strlen = $length - $at;
    		/**
    		 * Custom CSS text is expected to render inside an HTML STYLE element.
    		 * A STYLE closing tag must not appear within the CSS text because it
    		 * would close the element prematurely.
    		 *
    		 * The text must also *not* end with a partial closing tag (e.g., `<`,
    		 * `</`, … `</style`) because subsequent styles which are concatenated
    		 * could complete it, forming a valid `</style>` tag.
    		 *
    		 * Example:
    		 *
    		 *     $style_a = 'p { font-weight: bold; </sty';
    		 *     $style_b = 'le> gotcha!';
    		 *     $combined = "{$style_a}{$style_b}";
    		 *
    		 *     $style_a = 'p { font-weight: bold; </style';
    		 *     $style_b = 'p > b { color: red; }';
    		 *     $combined = "{$style_a}\n{$style_b}";
    		 *
    		 * Note how in the second example, both of the style contents are benign
    		 * when analyzed on their own. The first style was likely the result of
    		 * improper truncation, while the second is perfectly sound. It was only
    		 * through concatenation that these two styles combined to form content
    		 * that would have broken out of the containing STYLE element, thus
    		 * corrupting the page and potentially introducing security issues.
    		 *
    		 * @link https://html.spec.whatwg.org/multipage/parsing.html#rawtext-end-tag-name-state
    		 */
    		$possible_style_close_tag = 0 === substr_compare(
    			$css,
    			'</style',
    			$at,
    			min( 7, $remaining_strlen ),
    			true
    		);
    		if ( $possible_style_close_tag ) {
    			if ( $remaining_strlen < 8 ) {
    				return new WP_Error(
    					'rest_custom_css_illegal_markup',
    					sprintf(
    						/* translators: %s is the CSS that was provided. */
    						__( 'The CSS must not end in "%s".' ),
    						esc_html( substr( $css, $at ) )
    					),
    					array( 'status' => 400 )
    				);
    			}

    			if ( 1 === strspn( $css, " \t\f\r\n/>", $at + 7, 1 ) ) {
    				return new WP_Error(
    					'rest_custom_css_illegal_markup',
    					sprintf(
    						/* translators: %s is the CSS that was provided. */
    						__( 'The CSS must not contain "%s".' ),
    						esc_html( substr( $css, $at, 8 ) )
    					),
    					array( 'status' => 400 )
    				);
    			}
    		}
    	}

    	return true;
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/7.0/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php#L682)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/7.0/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php#L682-L753)

## 󠀁[Related](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#related)󠁿

| Uses | Description | 
| [__()](https://developer.wordpress.org/reference/functions/__/)`wp-includes/l10n.php` |

Retrieves the translation of $text.

  | 
| [esc_html()](https://developer.wordpress.org/reference/functions/esc_html/)`wp-includes/formatting.php` |

Escaping for HTML blocks.

  | 
| [WP_Error::__construct()](https://developer.wordpress.org/reference/classes/wp_error/__construct/)`wp-includes/class-wp-error.php` |

Initializes the error.

  |

[Show 1 more](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#)

| Used by | Description | 
| [WP_REST_Global_Styles_Controller::prepare_item_for_database()](https://developer.wordpress.org/reference/classes/wp_rest_global_styles_controller/prepare_item_for_database/)`wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php` |

Prepares a single global styles config for update.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/classes/WP_REST_Global_Styles_Controller/validate_custom_css/?output_format=md#changelog)󠁿

| Version | Description | 
| [7.0.0](https://developer.wordpress.org/reference/since/7.0.0/) | Only restricts contents which risk prematurely closing the STYLE element, either through a STYLE end tag or a prefix of one which might become a full end tag when combined with the contents of other styles. | 
| [6.4.0](https://developer.wordpress.org/reference/since/6.4.0/) | Changed method visibility to protected. | 
| [6.2.0](https://developer.wordpress.org/reference/since/6.2.0/) | Introduced. |

## User Contributed Notes

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Fclasses%2Fwp_rest_global_styles_controller%2Fvalidate_custom_css%2F)
before being able to contribute a note or feedback.