Adding the Property Attribute to Style Sheet Declarations in WordPress for HTML5 Validation

Of all the blogging platforms I’ve tried, WordPress is my favorite. If it is self-hosted, it is easy to customize.

One of the pitfalls of customization, however, is how easy it can be for a plugin of dubious quality to wreak havoc on your site. One of the problems I have had is that while WordPress does an excellent job at rendering valid HTML5 code, it is not difficult at all for a plugin to cause validation errors, even as a result of calling built-in WP functions.

In this case, a style sheet declaration was being triggered by a plugin using WP’s wp_register_style function. This function and the wp_enqueue_style function end up using the WP_Styles class, which is found in the /wp-includes/class.wp-styles.php file.

This class is called by WordPress and themes to insert link tags in the head section of your page. However, a plugin or theme can use the functions mentioned above to declare a CSS file anywhere on the page, inside or outside the head section.

This is not inherently problematic in that the page will be rendered normally. However, if the link tag is declared in the body of the HTML document rather than the head (as it happened in my case), the HTML5 code will not correctly validate if no property tag is present.

HTML5 validator error
No property attribute in a link tag not in the head? It won’t validate.

This line of code looks like it comes from a plugin, specifically the Comments Evolved (formerly known as “Google+ Comments for WordPress”) plugin. However, it is not – a little hacking on WordPress is in order here. Also, I’m going to report this as an issue so that the fix may be included in the next update.

If you open the file /wp-includes/class.wp-styles.php and add “property=’stylesheet'” to two lines (93 and 103 in my editor) as below, you shouldn’t see this problem again.

		$tag = apply_filters( 'style_loader_tag', "<link rel='$rel' property='stylesheet' id='$handle-css' $title href='$href' type='text/css' media='$media' />\n", $handle, $href );
		if ( 'rtl' === $this->text_direction && isset($obj->extra['rtl']) && $obj->extra['rtl'] ) {
			if ( is_bool( $obj->extra['rtl'] ) || 'replace' === $obj->extra['rtl'] ) {
				$suffix = isset( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
				$rtl_href = str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $this->_css_href( $obj->src , $ver, "$handle-rtl" ));
			} else {
				$rtl_href = $this->_css_href( $obj->extra['rtl'], $ver, "$handle-rtl" );
			}

			/** This filter is documented in wp-includes/class.wp-styles.php */
			$rtl_tag = apply_filters( 'style_loader_tag', "<link rel='$rel' property='stylesheet' id='$handle-rtl-css' $title href='$rtl_href' type='text/css' media='$media' />\n", $handle, $rtl_href );

			if ( $obj->extra['rtl'] === 'replace' ) {
				$tag = $rtl_tag;
			} else {
				$tag .= $rtl_tag;
			}
		}

This will not fix any plugins or themes that use another mechanism to declare style sheets outside the head, but it has fixed several errors caused by plugins.

Leave a Reply