diff --git wp-includes/class.wp-scripts.php wp-includes/class.wp-scripts.php
index b0077a2..62e1f56 100644
--- wp-includes/class.wp-scripts.php
+++ wp-includes/class.wp-scripts.php
@@ -82,26 +82,30 @@ class WP_Scripts extends WP_Dependencies {
 	}
 
 	public function do_item( $handle, $group = false ) {
-		if ( !parent::do_item($handle) )
+		if ( !parent::do_item( $handle ) ) {
 			return false;
+		}
 
-		if ( 0 === $group && $this->groups[$handle] > 0 ) {
+		if ( 0 === $group && $this->groups[ $handle ] > 0 ) {
 			$this->in_footer[] = $handle;
 			return false;
 		}
 
-		if ( false === $group && in_array($handle, $this->in_footer, true) )
+		if ( false === $group && in_array($handle, $this->in_footer, true) ) {
 			$this->in_footer = array_diff( $this->in_footer, (array) $handle );
+		}
 
-		if ( null === $this->registered[$handle]->ver )
+		if ( null === $this->registered[ $handle ]->ver ) {
 			$ver = '';
-		else
-			$ver = $this->registered[$handle]->ver ? $this->registered[$handle]->ver : $this->default_version;
+		} else {
+			$ver = $this->registered[ $handle ]->ver ? $this->registered[ $handle ]->ver : $this->default_version;
+		}
 
-		if ( isset($this->args[$handle]) )
-			$ver = $ver ? $ver . '&amp;' . $this->args[$handle] : $this->args[$handle];
+		if ( isset( $this->args[ $handle ] ) ) {
+			$ver = $ver ? $ver . '&amp;' . $this->args[ $handle ] : $this->args[ $handle ];
+		}
 
-		$src = $this->registered[$handle]->src;
+		$src = $this->registered[ $handle ]->src;
 
 		if ( $this->do_concat ) {
 			/**
@@ -113,7 +117,7 @@ class WP_Scripts extends WP_Dependencies {
 			 * @param string $handle Script handle.
 			 */
 			$srce = apply_filters( 'script_loader_src', $src, $handle );
-			if ( $this->in_default_dir($srce) ) {
+			if ( $this->in_default_dir( $srce ) ) {
 				$this->print_code .= $this->print_extra_script( $handle, false );
 				$this->concat .= "$handle,";
 				$this->concat_version .= "$handle$ver";
@@ -124,40 +128,90 @@ class WP_Scripts extends WP_Dependencies {
 			}
 		}
 
-		$this->print_extra_script( $handle );
-		if ( !preg_match('|^(https?:)?//|', $src) && ! ( $this->content_url && 0 === strpos($src, $this->content_url) ) ) {
-			$src = $this->base_url . $src;
-		}
+ 		$this->print_extra_script( $handle );
+		if ( !preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && 0 === strpos( $src, $this->content_url ) ) ) {
+ 			$src = $this->base_url . $src;
+ 		}
 
-		if ( !empty($ver) )
-			$src = add_query_arg('ver', $ver, $src);
+		if ( !empty( $ver ) ) {
+			$src = add_query_arg( 'ver', $ver, $src );
+		}
 
 		/** This filter is documented in wp-includes/class.wp-scripts.php */
 		$src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
 
-		if ( ! $src )
+		if ( ! $src ) {
 			return true;
+		}
+
 
-		$tag = "<script type='text/javascript' src='$src'></script>\n";
+		$attributes = $this->get_script_attributes( $handle, $src );
+		$script_tag = "<script$attributes></script>\n";
 
-		/** 
+		/**
 		 * Filter the HTML script tag of an enqueued script.
 		 *
 		 * @since 4.1.0
 		 *
-		 * @param string $tag    The `<script>` tag for the enqueued script.
-		 * @param string $handle The script's registered handle.
-		 * @param string $src    The script's source URL.
+		 * @param string $script_tag The `<script>` tag for the enqueued script.
+		 * @param string $handle     The script's registered handle.
+		 * @param string $src        The script's source URL.
 		 */
-		$tag = apply_filters( 'script_loader_tag', $tag, $handle, $src );
+		$script_tag = apply_filters( 'script_loader_tag', $script_tag, $handle, $src );
 
 		if ( $this->do_concat ) {
-			$this->print_html .= $tag;
+			$this->print_html .= $script_tag;
 		} else {
-			echo $tag;
+			echo $script_tag;
 		}
 
-		return true;
+ 		return true;
+	}
+
+ 	/**
+	 * Concatenates attributes for the script tag
+	 *
+	 * @since  4.0.0
+	 *
+	 * @param  string $handle Script registered handle
+	 * @param  string $src    Script registered src
+	 *
+	 * @return string         Concatenated attributes string
+	 */
+	public function get_script_attributes( $handle, $src ) {
+
+		$default_attributes = array(
+			'type' => 'text/javascript',
+			'src'  => $src,
+		);
+
+		$attributes = isset( $this->registered[ $handle ]->args['attributes'] )
+			? (array) $this->registered[ $handle ]->args['attributes']
+			: array();
+
+		$attributes = wp_parse_args( $attributes, $default_attributes );
+
+		/**
+		 * Filter the script loader attributes.
+		 *
+		 * @since 4.1.0
+		 *
+		 * @param array  $attributes Array of script tag attributes.
+		 * @param string $handle     Script handle.
+		 * @param string $src        Script loader source path.
+		 */
+		$attributes = apply_filters( 'script_loader_attributes', $attributes, $handle, $src );
+		// Ensure source is set
+		$attributes['src'] = isset( $attributes['src'] ) ? $attributes['src'] : $src;
+
+		$concat_attributes = '';
+		foreach ( $attributes as $attribute => $attribute_value ) {
+			if ( ! is_null( $attribute ) && ! is_null( $attribute_value ) ) {
+				$concat_attributes .= ' '. esc_attr( $attribute ) .'="'. esc_attr( $attribute_value ) .'"';
+			}
+		}
+
+		return $concat_attributes;
 	}
 
 	/**
diff --git wp-includes/class.wp-styles.php wp-includes/class.wp-styles.php
index 5147926..00a31f2 100644
--- wp-includes/class.wp-styles.php
+++ wp-includes/class.wp-styles.php
@@ -40,20 +40,20 @@ class WP_Styles extends WP_Dependencies {
 	}
 
 	public function do_item( $handle ) {
-		if ( !parent::do_item($handle) )
+		if ( !parent::do_item( $handle ) )
 			return false;
 
-		$obj = $this->registered[$handle];
+		$obj = $this->registered[ $handle ];
 		if ( null === $obj->ver )
 			$ver = '';
 		else
 			$ver = $obj->ver ? $obj->ver : $this->default_version;
 
-		if ( isset($this->args[$handle]) )
-			$ver = $ver ? $ver . '&amp;' . $this->args[$handle] : $this->args[$handle];
+		if ( isset( $this->args[ $handle ] ) )
+			$ver = $ver ? $ver . '&amp;' . $this->args[ $handle ] : $this->args[ $handle ];
 
 		if ( $this->do_concat ) {
-			if ( $this->in_default_dir($obj->src) && !isset($obj->extra['conditional']) && !isset($obj->extra['alt']) ) {
+			if ( $this->in_default_dir( $obj->src ) && !isset( $obj->extra['conditional'] ) && !isset( $obj->extra['alt'] ) ) {
 				$this->concat .= "$handle,";
 				$this->concat_version .= "$handle$ver";
 
@@ -63,18 +63,13 @@ class WP_Styles extends WP_Dependencies {
 			}
 		}
 
-		if ( isset($obj->args) )
-			$media = esc_attr( $obj->args );
-		else
-			$media = 'all';
-
 		$href = $this->_css_href( $obj->src, $ver, $handle );
 		if ( empty( $href ) ) {
 			// Turns out there is nothing to print.
 			return true;
 		}
-		$rel = isset($obj->extra['alt']) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
-		$title = isset($obj->extra['title']) ? "title='" . esc_attr( $obj->extra['title'] ) . "'" : '';
+
+		$attributes = $this->get_style_attributes( $handle, $href );
 
 		/**
 		 * Filter the HTML link tag of an enqueued style.
@@ -84,17 +79,18 @@ class WP_Styles extends WP_Dependencies {
 		 * @param string         The link tag for the enqueued style.
 		 * @param string $handle The style's registered handle.
 		 */
-		$tag = apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-css' $title href='$href' type='text/css' media='$media' />\n", $handle );
-		if ( 'rtl' === $this->text_direction && isset($obj->extra['rtl']) && $obj->extra['rtl'] ) {
+		$tag = apply_filters( 'style_loader_tag', "<link$attributes/>\n", $handle );
+		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" ));
+				$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" );
 			}
 
+			$rtl_attributes = $this->get_style_attributes( $handle, $rtl_href, true );
 			/** This filter is documented in wp-includes/class.wp-styles.php */
-			$rtl_tag = apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-rtl-css' $title href='$rtl_href' type='text/css' media='$media' />\n", $handle );
+			$rtl_tag = apply_filters( 'style_loader_tag', "<link$rtl_attributes/>\n", $handle );
 
 			if ( $obj->extra['rtl'] === 'replace' ) {
 				$tag = $rtl_tag;
@@ -119,6 +115,69 @@ class WP_Styles extends WP_Dependencies {
 		return true;
 	}
 
+	/**
+	 * Concatenates attributes for the style tag
+	 *
+	 * @since  4.1.0
+	 *
+	 * @param  string $handle style registered handle
+	 * @param  string $href   style registered href
+	 *
+	 * @return string         Concatenated attributes string
+	 */
+	public function get_style_attributes( $handle, $href, $rtl = false ) {
+
+		$default_attributes = array(
+			'id'    => "$handle-css",
+			'rel'   => 'stylesheet',
+			'type'  => 'text/css',
+			'media' => 'all',
+		);
+
+		if ( $rtl ) {
+			$default_attributes['id'] = "$handle-rtl-css";
+		}
+
+		$obj = $this->registered[ $handle ];
+
+		$attributes = isset( $obj->args )
+			? (array) $obj->args
+			: array();
+
+		$attributes = wp_parse_args( $attributes, $default_attributes );
+
+		if ( isset( $obj->extra['alt'] ) && $obj->extra['alt'] ) {
+			$attributes['rel'] = 'alternate stylesheet';
+		}
+
+		if ( isset( $obj->extra['title'] ) ) {
+			$attributes['title'] = esc_attr( $obj->extra['title'] );
+		}
+
+		/**
+		 * Filter the style loader attributes.
+		 *
+		 * @since 4.1.0
+		 *
+		 * @param array  $attributes Array of style tag attributes.
+		 * @param string $handle     Style handle.
+		 * @param string $href        Style loader source path.
+		 */
+		$attributes = apply_filters( 'style_loader_attributes', $attributes, $handle, $href );
+
+		// Ensure href is set
+		$attributes['href'] = isset( $attributes['href'] ) ? $attributes['href'] : $href;
+
+		$concat_attributes = '';
+		foreach ( $attributes as $attribute => $attribute_value ) {
+			if ( ! is_null( $attribute ) && ! is_null( $attribute_value ) ) {
+				$concat_attributes .= ' '. esc_attr( $attribute ) .'="'. esc_attr( $attribute_value ) .'"';
+			}
+		}
+
+		return $concat_attributes;
+	}
+
 	public function add_inline_style( $handle, $code ) {
 		if ( ! $code ) {
 			return false;
diff --git wp-includes/functions.wp-scripts.php wp-includes/functions.wp-scripts.php
index 8c3151c..876f2eb 100644
--- wp-includes/functions.wp-scripts.php
+++ wp-includes/functions.wp-scripts.php
@@ -67,11 +67,22 @@ function wp_print_scripts( $handles = false ) {
  *                               to end of path as a query string. If no version is specified or set to false, a version
  *                               number is automatically added equal to current installed WordPress version.
  *                               If set to null, no version is added. Default 'false'. Accepts 'false', 'null', or 'string'.
- * @param bool        $in_footer Optional. Whether to enqueue the script before </head> or before </body>.
- *                               Default 'false'. Accepts 'false' or 'true'.
+ * @param array       $args      Optional script arguments.
+ * - bool  - in_footer  - Whether to enqueue the script before </head> or before </body>. Default 'false'. Accepts 'false' or 'true'.
+ * - array - attributes - Array of script tag attributes. Default: array( 'type' => 'text/javascript' )
  */
-function wp_register_script( $handle, $src, $deps = array(), $ver = false, $in_footer = false ) {
+function wp_register_script( $handle, $src, $deps = array(), $ver = false, $args = array() ) {
 	global $wp_scripts;
+
+	// For back-compat. If it's not an array, convert to boolean.
+	$args = ! is_array( $args ) ? array( 'in_footer' => (bool) $args ) : $args;
+	$args = wp_parse_args( $args, array(
+		'in_footer'  => false,
+		'attributes' => array(),
+	) );
+
+	$attributes = wp_parse_args( $args['attributes'], array( 'type' => 'text/javascript' ) );
+
 	if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
 		if ( ! did_action( 'init' ) )
 			_doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
@@ -79,9 +90,10 @@ function wp_register_script( $handle, $src, $deps = array(), $ver = false, $in_f
 		$wp_scripts = new WP_Scripts();
 	}
 
-	$wp_scripts->add( $handle, $src, $deps, $ver );
-	if ( $in_footer )
+	$wp_scripts->add( $handle, $src, $deps, $ver, array( 'attributes' => $attributes ) );
+	if ( $args['in_footer'] ) {
 		$wp_scripts->add_data( $handle, 'group', 1 );
+	}
 }
 
 /**
@@ -184,18 +196,29 @@ function wp_deregister_script( $handle ) {
  * @global WP_Scripts $wp_scripts The WP_Scripts object for printing scripts.
  *
  * @since 2.6.0
-
+ *
  * @param string      $handle    Name of the script.
  * @param string|bool $src       Path to the script from the root directory of WordPress. Example: '/js/myscript.js'.
  * @param array       $deps      An array of registered handles this script depends on. Default empty array.
  * @param string|bool $ver       Optional. String specifying the script version number, if it has one. This parameter
  *                               is used to ensure that the correct version is sent to the client regardless of caching,
  *                               and so should be included if a version number is available and makes sense for the script.
- * @param bool        $in_footer Optional. Whether to enqueue the script before </head> or before </body>.
- *                               Default 'false'. Accepts 'false' or 'true'.
+ * @param array       $args      Optional script arguments.
+ * - bool  - in_footer  - Whether to enqueue the script before </head> or before </body>. Default 'false'. Accepts 'false' or 'true'.
+ * - array - attributes - Array of script tag attributes. Default: array( 'type' => 'text/javascript' )
  */
-function wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) {
+function wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $args = array() ) {
 	global $wp_scripts;
+
+	// For back-compat. If it's not an array, convert to boolean.
+	$args = ! is_array( $args ) ? array( 'in_footer' => (bool) $args ) : $args;
+	$args = wp_parse_args( $args, array(
+		'in_footer'  => false,
+		'attributes' => array(),
+	) );
+
+	$attributes = wp_parse_args( $args['attributes'], array( 'type' => 'text/javascript' ) );
+
 	if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
 		if ( ! did_action( 'init' ) )
 			_doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
@@ -205,9 +228,10 @@ function wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false
 
 	if ( $src ) {
 		$_handle = explode('?', $handle);
-		$wp_scripts->add( $_handle[0], $src, $deps, $ver );
-		if ( $in_footer )
+		$wp_scripts->add( $_handle[0], $src, $deps, $ver, array( 'attributes' => $attributes ) );
+		if ( $args['in_footer'] ) {
 			$wp_scripts->add_data( $_handle[0], 'group', 1 );
+		}
 	}
 	$wp_scripts->enqueue( $handle );
 }
diff --git wp-includes/functions.wp-styles.php wp-includes/functions.wp-styles.php
index 83db482..4fad854 100644
--- wp-includes/functions.wp-styles.php
+++ wp-includes/functions.wp-styles.php
@@ -91,17 +91,27 @@ function wp_add_inline_style( $handle, $data ) {
  *
  * @since 2.6.0
  *
- * @param string      $handle Name of the stylesheet.
- * @param string|bool $src    Path to the stylesheet from the WordPress root directory. Example: '/css/mystyle.css'.
- * @param array       $deps   An array of registered style handles this stylesheet depends on. Default empty array.
- * @param string|bool $ver    String specifying the stylesheet version number. Used to ensure that the correct version
- *                            is sent to the client regardless of caching. Default 'false'. Accepts 'false', 'null', or 'string'.
- * @param string      $media  Optional. The media for which this stylesheet has been defined.
- *                            Default 'all'. Accepts 'all', 'aural', 'braille', 'handheld', 'projection', 'print',
- *                            'screen', 'tty', or 'tv'.
+ * @param string        $handle Name of the stylesheet.
+ * @param string|bool   $src    Path to the stylesheet from the WordPress root directory. Example: '/css/mystyle.css'.
+ * @param array         $deps   An array of registered style handles this stylesheet depends on. Default empty array.
+ * @param string|bool   $ver    String specifying the stylesheet version number. Used to ensure that the correct version
+ *                              is sent to the client regardless of caching. Default 'false'. Accepts 'false', 'null', or 'string'.
+ * @param string|array  $atts   Optional style link tag attributes or string. If an array sets the attributes for the style link
+ *                              tag. Default: array( "rel" => "stylesheet", "type" => "text/css", "media" => "all" )
+ *                              If a string sets the media for which this stylesheet has been defined. Default 'all'. Accepts 'all',
+ *                              'aural', 'braille', 'handheld', 'projection', 'print', 'screen', 'tty', or 'tv'.
  */
-function wp_register_style( $handle, $src, $deps = array(), $ver = false, $media = 'all' ) {
+function wp_register_style( $handle, $src, $deps = array(), $ver = false, $atts = array() ) {
 	global $wp_styles;
+
+	// For back-compat. If it's not an array, convert to media string.
+	$atts = ! is_array( $atts ) ? array( 'media' => $atts ) : $atts;
+	$atts = wp_parse_args( $atts, array(
+		'rel'   => 'stylesheet',
+		'type'  => 'text/css',
+		'media' => 'all',
+	) );
+
 	if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
 		if ( ! did_action( 'init' ) )
 			_doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
@@ -109,7 +119,7 @@ function wp_register_style( $handle, $src, $deps = array(), $ver = false, $media
 		$wp_styles = new WP_Styles();
 	}
 
-	$wp_styles->add( $handle, $src, $deps, $ver, $media );
+	$wp_styles->add( $handle, $src, $deps, $ver, $atts );
 }
 
 /**
@@ -145,18 +155,28 @@ function wp_deregister_style( $handle ) {
  *
  * @since 2.6.0
  *
- * @param string      $handle Name of the stylesheet.
- * @param string|bool $src    Path to the stylesheet from the root directory of WordPress. Example: '/css/mystyle.css'.
- * @param array       $deps   An array of registered style handles this stylesheet depends on. Default empty array.
- * @param string|bool $ver    String specifying the stylesheet version number, if it has one. This parameter is used
- *                            to ensure that the correct version is sent to the client regardless of caching, and so
- *                            should be included if a version number is available and makes sense for the stylesheet.
- * @param string      $media  Optional. The media for which this stylesheet has been defined.
- *                            Default 'all'. Accepts 'all', 'aural', 'braille', 'handheld', 'projection', 'print',
- *                            'screen', 'tty', or 'tv'.
+ * @param string        $handle Name of the stylesheet.
+ * @param string|bool   $src    Path to the stylesheet from the root directory of WordPress. Example: '/css/mystyle.css'.
+ * @param array         $deps   An array of registered style handles this stylesheet depends on. Default empty array.
+ * @param string|bool   $ver    String specifying the stylesheet version number, if it has one. This parameter is used
+ *                              to ensure that the correct version is sent to the client regardless of caching, and so
+ *                              should be included if a version number is available and makes sense for the stylesheet.
+ * @param string|array  $atts   Optional style link tag attributes or string. If an array sets the attributes for the style link
+ *                              tag. Default: array( "rel" => "stylesheet", "type" => "text/css", "media" => "all" )
+ *                              If a string sets the media for which this stylesheet has been defined. Default 'all'. Accepts 'all',
+ *                              'aural', 'braille', 'handheld', 'projection', 'print', 'screen', 'tty', or 'tv'.
  */
-function wp_enqueue_style( $handle, $src = false, $deps = array(), $ver = false, $media = 'all' ) {
+function wp_enqueue_style( $handle, $src = false, $deps = array(), $ver = false, $atts = array() ) {
 	global $wp_styles;
+
+	// For back-compat. If it's not an array, convert to media string.
+	$atts = ! is_array( $atts ) ? array( 'media' => $atts ) : $atts;
+	$atts = wp_parse_args( $atts, array(
+		'rel'   => 'stylesheet',
+		'type'  => 'text/css',
+		'media' => 'all',
+	) );
+
 	if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
 		if ( ! did_action( 'init' ) )
 			_doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
@@ -166,7 +186,7 @@ function wp_enqueue_style( $handle, $src = false, $deps = array(), $ver = false,
 
 	if ( $src ) {
 		$_handle = explode('?', $handle);
-		$wp_styles->add( $_handle[0], $src, $deps, $ver, $media );
+		$wp_styles->add( $_handle[0], $src, $deps, $ver, $atts );
 	}
 	$wp_styles->enqueue( $handle );
 }
