Index: wp-includes/class.wp-scripts.php
===================================================================
--- wp-includes/class.wp-scripts.php	(revision 38434)
+++ wp-includes/class.wp-scripts.php	(working copy)
@@ -341,8 +341,44 @@
 
 		if ( ! $src )
 			return true;
+      
+    $extra_attributes = isset( $obj->extra['attributes'] ) && is_array( $obj->extra['attributes'] ) ? $obj->extra['attributes'] : array();
+    
+    /**
+		 * Filters the additional attribute names and values for the the script tag
+		 *
+		 * @since joe_bopper patch
+		 *
+		 * @param array $extra_attributes The current name-value pairs.
+		 * @param string $handle          The script's registered handle.
+		 */
+    $extra_attributes = apply_filters( 'script_loader_extra_attributes', $extra_attributes, $handle );
+    
+    //prevent conflict of script attributes
+    unset( $extra_attributes['type'], $extra_attributes['src'] );
+    
+    $attributes_str = "";
+    $attributes_applied = array();
+    foreach( $extra_attributes as $attr_name => $attr_value ){
+      /**
+       * Filters the value for a given attribute of the the script tag
+       *
+       * @since joe_bopper patch
+       *
+       * @param array $attr_value The current attribute value.
+       * @param string $handle    The script's registered handle.
+       */
+      $attr_value = esc_attr( apply_filters( "script_loader_{$attr_name}_attribute", $attr_value, $handle ) );
+      $attr_name = esc_attr_name( $attr_name );
+      
+      //prevent duplication conflict
+      if( $attr_name && ! in_array( $attr_name, $attributes_applied ) ){
+        $attributes_str .= " {$attr_name}='{$attr_value}'";
+        $attributes_applied[] = $attr_name;
+      }
+    }
 
-		$tag = "{$cond_before}{$before_handle}<script type='text/javascript' src='$src'></script>\n{$after_handle}{$cond_after}";
+		$tag = "{$cond_before}{$before_handle}<script type='text/javascript' src='$src'{$attributes_str}></script>\n{$after_handle}{$cond_after}";
 
 		/**
 		 * Filters the HTML script tag of an enqueued script.
Index: wp-includes/class.wp-styles.php
===================================================================
--- wp-includes/class.wp-styles.php	(revision 38434)
+++ wp-includes/class.wp-styles.php	(working copy)
@@ -188,6 +188,42 @@
 		$rel = isset($obj->extra['alt']) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
 		$title = isset($obj->extra['title']) ? "title='" . esc_attr( $obj->extra['title'] ) . "'" : '';
 
+    $extra_attributes = isset( $obj->extra['attributes'] ) && is_array( $obj->extra['attributes'] ) ? $obj->extra['attributes'] : array();
+    
+    /**
+		 * Filters the additional attribute names and values for the the style tag
+		 *
+		 * @since joe_bopper patch
+		 *
+		 * @param array $extra_attributes The current name-value pairs.
+		 * @param string $handle          The style's registered handle.
+		 */
+    $extra_attributes = apply_filters( 'style_loader_extra_attributes', $extra_attributes, $handle );
+    
+    //prevent conflict of style attributes
+    unset( $extra_attributes['rel'], $extra_attributes['id'], $extra_attributes['title'], $extra_attributes['href'], $extra_attributes['type'], $extra_attributes['media'] );
+    
+    $attributes_str = "";
+    $attributes_applied = array();
+    foreach( $extra_attributes as $attr_name => $attr_value ){
+      /**
+       * Filters the value for a given attribute of the the style tag
+       *
+       * @since joe_bopper patch
+       *
+       * @param array $attr_value The current attribute value.
+       * @param string $handle    The style's registered handle.
+       */
+      $attr_value = esc_attr( apply_filters( "style_loader_{$attr_name}_attribute", $attr_value, $handle ) );
+      $attr_name = esc_attr_name( $attr_name );
+      
+      //prevent duplication conflict
+      if( $attr_name && ! in_array( $attr_name, $attributes_applied ) ){
+        $attributes_str .= " {$attr_name}='{$attr_value}'";
+        $attributes_applied[] = $attr_name;
+      }
+    }
+
 		/**
 		 * Filters the HTML link tag of an enqueued style.
 		 *
@@ -200,7 +236,7 @@
 		 * @param string $href   The stylesheet's source URL.
 		 * @param string $media  The stylesheet's media attribute.
 		 */
-		$tag = apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-css' $title href='$href' type='text/css' media='$media' />\n", $handle, $href, $media);
+		$tag = apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-css' $title href='$href' type='text/css' media='$media'{$attributes_str} />\n", $handle, $href, $media);
 		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'] : '';
@@ -210,7 +246,7 @@
 			}
 
 			/** 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_href, $media );
+			$rtl_tag = apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-rtl-css' $title href='$rtl_href' type='text/css' media='$media'{$attributes_str} />\n", $handle, $rtl_href, $media );
 
 			if ( $obj->extra['rtl'] === 'replace' ) {
 				$tag = $rtl_tag;
Index: wp-includes/formatting.php
===================================================================
--- wp-includes/formatting.php	(revision 38434)
+++ wp-includes/formatting.php	(working copy)
@@ -3947,6 +3947,34 @@
 }
 
 /**
+ * Escaping for HTML attributes.
+ *
+ * @since 2.8.0
+ *
+ * @param string $text
+ * @return string
+ */
+function esc_attr_name( $text ) {
+	$safe_text = wp_check_invalid_utf8( $text );
+	$safe_text = preg_replace( '/[\t\n\f \/>"\'=]+/', '_', $safe_text );
+	/**
+	 * Filters a string cleaned and escaped for output as an HTML attribute name.
+	 *
+	 * Text passed to esc_attr_name() is stripped of invalid or special characters
+	 * before output.
+	 *
+	 * @since joe_bopper patch
+	 *
+	 * @param string $safe_text The text after it has been escaped.
+ 	 * @param string $text      The text prior to being escaped.
+	 */
+	$safe_text = apply_filters( 'attribute_name_escape', $safe_text, $text );
+  
+  //Notably, an attribute name cannot be an empty string.
+  return $safe_text ? $safe_text : 'empty_string_supplied_as_attribute_name';
+}
+
+/**
  * Escaping for textarea values.
  *
  * @since 3.1.0
Index: wp-includes/functions.wp-scripts.php
===================================================================
--- wp-includes/functions.wp-scripts.php	(revision 38434)
+++ wp-includes/functions.wp-scripts.php	(working copy)
@@ -323,7 +323,7 @@
  *
  * @since 4.2.0
  *
- * @see WP_Dependency::add_data()
+ * @see WP_Dependencies::add_data()
  *
  * @param string $handle Name of the script.
  * @param string $key    Name of data point for which we're storing a value.
@@ -333,3 +333,79 @@
 function wp_script_add_data( $handle, $key, $value ){
 	return wp_scripts()->add_data( $handle, $key, $value );
 }
+
+/**
+ * Get the additional attributes metadata of a script.
+ *
+ * Works only if the script has already been registered.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle Name of the script.
+ * @return array Name-value attribute pairs.
+ */
+function wp_script_get_extra_attributes( $handle ) {
+  $wp_scripts = wp_scripts();
+  $attrs = isset( $wp_scripts->registered[$handle]->extra['attributes'] ) ? (array)$wp_scripts->registered[$handle]->extra['attributes'] : array();
+  return $attrs;
+}
+
+/**
+ * Add additional attributes as metadata of a script.
+ *
+ * Works only if the script has already been registered.
+ * 
+ * Possible values include: 'integrity', 'crossorigin', 'hreflang', 'data-*',...
+ * Does not add 'type' or 'src' attributes due to potential conflicts.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle           Name of the script.
+ * @param array  $additional_attrs Name-value attribute pairs to add
+ * @return bool True on success, false on failure.
+ */
+function wp_script_add_extra_attributes( $handle, $additional_attrs ) {
+  //remove conflicting attributes
+  unset( $additional_attrs['type'], $additional_attrs['src'] );
+  
+  $curr_attrs = wp_script_get_extra_attributes( $handle );
+  $new_attrs = array_merge( $curr_attrs, $additional_attrs );
+  
+  return wp_script_add_data( $handle, 'attributes', $new_attrs );
+}
+
+/**
+ * Add additional attributes as metadata of a script.
+ *
+ * Works only if the script has already been registered.
+ * Does not add 'type' or 'src' attributes.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle         Name of the script.
+ * @param array  $unwanted_attrs Names of the attributes to delete
+ * @return bool True on success, false on failure.
+ */
+function wp_script_delete_extra_attributes( $handle, $unwanted_attrs ) {
+  
+  $curr_attrs = wp_script_get_extra_attributes( $handle );
+  $attrs = array_diff_key( $curr_attrs, array_flip( $unwanted_attrs ) );
+  
+  return wp_script_add_data( $handle, 'attributes', $attrs );
+}
+
+/**
+ * Add subresource integrity (SRI) attributes to a script
+ *
+ * Works only if the script has already been registered.
+ * Does not add 'type' or 'src' attributes.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle         Name of the script.
+ * @param array  $unwanted_attrs Names of the attributes to delete
+ * @return bool True on success, false on failure.
+ */
+function wp_script_integrity( $handle, $hash, $crossorigin = 'anonymous' ) {
+  wp_script_add_extra_attributes( $handle, array( 'integrity' => $hash, 'crossorigin' => $crossorigin ) );
+}
Index: wp-includes/functions.wp-styles.php
===================================================================
--- wp-includes/functions.wp-styles.php	(revision 38434)
+++ wp-includes/functions.wp-styles.php	(working copy)
@@ -214,6 +214,7 @@
  * 'suffix'      string      Optional suffix, used in combination with RTL.
  * 'alt'         bool        For rel="alternate stylesheet".
  * 'title'       string      For preferred/alternate stylesheets.
+ * 'attributes'  array       Additional attributes (e.g. integrity, data-*) and their values
  *
  * @see WP_Dependency::add_data()
  *
@@ -228,3 +229,79 @@
 function wp_style_add_data( $handle, $key, $value ) {
 	return wp_styles()->add_data( $handle, $key, $value );
 }
+
+/**
+ * Get the additional attributes metadata of a style.
+ *
+ * Works only if the style has already been registered.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle Name of the style.
+ * @return array Name-value attribute pairs.
+ */
+function wp_style_get_extra_attributes( $handle ) {
+  $wp_styles = wp_styles();
+  $attrs = isset( $wp_styles->registered[$handle]->extra['attributes'] ) ? (array)$wp_styles->registered[$handle]->extra['attributes'] : array();
+  return $attrs;
+}
+
+/**
+ * Add additional attributes as metadata of a style.
+ *
+ * Works only if the style has already been registered.
+ * 
+ * Possible values include: 'integrity', 'crossorigin', 'hreflang', 'data-*',...
+ * Does not add 'rel', 'id', 'title', 'href', 'type', or 'media' attributes due to potential conflicts.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle           Name of the style.
+ * @param array  $additional_attrs Name-value attribute pairs to add
+ * @return bool True on success, false on failure.
+ */
+function wp_style_add_extra_attributes( $handle, $additional_attrs ) {
+  //remove conflicting attributes
+  unset( $additional_attrs['rel'], $additional_attrs['id'], $additional_attrs['title'], $additional_attrs['href'], $additional_attrs['type'], $additional_attrs['media'] );
+  
+  $curr_attrs = wp_style_get_extra_attributes( $handle );
+  $new_attrs = array_merge( $curr_attrs, $additional_attrs );
+  
+  return wp_style_add_data( $handle, 'attributes', $new_attrs );
+}
+
+/**
+ * Add additional attributes as metadata of a style.
+ *
+ * Works only if the style has already been registered.
+ * Does not add 'type' or 'src' attributes.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle         Name of the style.
+ * @param array  $unwanted_attrs Names of the attributes to delete
+ * @return bool True on success, false on failure.
+ */
+function wp_style_delete_extra_attributes( $handle, $unwanted_attrs ) {
+  
+  $curr_attrs = wp_style_get_extra_attributes( $handle );
+  $attrs = array_diff_key( $curr_attrs, array_flip( $unwanted_attrs ) );
+  
+  return wp_style_add_data( $handle, 'attributes', $attrs );
+}
+
+/**
+ * Add subresource integrity (SRI) attributes to a style
+ *
+ * Works only if the style has already been registered.
+ * Does not add 'type' or 'src' attributes.
+ *
+ * @since joe_bopper patch
+ *
+ * @param string $handle         Name of the style.
+ * @param array  $unwanted_attrs Names of the attributes to delete
+ * @return bool True on success, false on failure.
+ */
+function wp_style_integrity( $handle, $hash, $crossorigin = 'anonymous' ) {
+  wp_style_add_extra_attributes( $handle, array( 'integrity' => $hash, 'crossorigin' => $crossorigin ) );
+}
