Remove the type Attribute from Script and Style Tags in WordPress

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.