When you run a WordPress site through the W3C validator, you will likely see multiple warnings about the type attribute on <script> and <style> tags. In HTML5, type="text/javascript" and type="text/css" are redundant — the browser already assumes those MIME types by default. WordPress adds them anyway for backwards compatibility.
Problem: WordPress outputs type="text/javascript" on <script> tags and type="text/css" on <link> tags, which are redundant in HTML5 and fail validator checks.
Solution: Use preg_replace() inside the script_loader_tag and style_loader_tag filters to strip the type attribute. Apply the filter selectively per handle to avoid affecting third-party scripts that may rely on the attribute being present.
There are three common approaches to remove these attributes. The first two use preg_replace to strip the attribute from the tag string, but they fail to cover scripts localised with wp_localize_script() because that function outputs an inline <script> tag outside the filter pipeline.
Approach 1 — filters on individual tags:
<?php
add_filter( 'style_loader_tag', 'remove_type_attr', 10, 2 );
add_filter( 'script_loader_tag', 'remove_type_attr', 10, 2 );
function remove_type_attr( $tag ) {
return preg_replace( "/ type=['"]text\/(javascript|css)['"]/", '', $tag );
}
Approach 2 — output buffer on the entire page. This catches every tag including those injected by wp_localize_script():
<?php
add_action( 'template_redirect', 'start_type_attr_removal_buffer' );
function start_type_attr_removal_buffer() {
ob_start( function ( $buffer ) {
return preg_replace( "/ type=['"]text\/(javascript|css)['"]/", '', $buffer );
} );
}
The template_redirect hook fires early enough to wrap the entire front-end output, so all rendered <script> and <style> tags — whether enqueued normally, localised, or inline — have the type attribute removed before the response is sent.
NOTE: Starting an output buffer on every page request adds a small amount of memory and processing overhead. On high-traffic sites, measure the impact before deploying to production. For most WordPress sites the difference is negligible, but it is worth knowing.