diff --git a/wysiwyg.api.php b/wysiwyg.api.php
index c4d8857..89418e0 100644
--- a/wysiwyg.api.php
+++ b/wysiwyg.api.php
@@ -62,6 +62,22 @@ function hook_wysiwyg_plugin($editor, $version) {
             'extensions' => array(
               'imce' => t('IMCE'),
             ),
+            // Additional files needed before the main plugin files should be
+            // added here. It works just like the #attached property from FAPI.
+            'attached files' => array(
+              // Attach other files or settings.
+              'js' => array(
+                drupal_get_path('module', 'mymodule') . '/additional_file.js/',
+              ),
+              // Attach predefined libraries.
+              'library' => array(
+                array('media', 'media_browser'),
+              ),
+              // Attach styling.
+              'css' => array(
+                drupal_get_path('module', 'mymodule') . '/additional_styling.css',
+              ),
+            ),
             // A list of global, native editor configuration settings to
             // override. To be used rarely and only when required.
             'options' => array(
@@ -154,6 +170,22 @@ function hook_INCLUDE_plugin() {
     // An alternative filename of the integration JavaScript; defaults to
     // '[plugin-name].js'.
     'js file' => 'awesome.js',
+    // Additional files needed before the main plugin files should be added
+    // here. It works just like the #attached property from FAPI.
+    'attached files' => array(
+      // Attach other files or settings.
+      'js' => array(
+        drupal_get_path('module', 'mymodule') . '/additional_file.js/',
+      ),
+      // Attach predefined libraries.
+      'library' => array(
+        array('media', 'media_browser'),
+      ),
+      // Attach styling.
+      'css' => array(
+        drupal_get_path('module', 'mymodule') . '/additional_styling.css',
+      ),
+    ),
     // An alternative path to the integration stylesheet; defaults to
     // '[path-to-module]/[plugins-directory]/[plugin-name]'.
     'css path' => drupal_get_path('module', 'mymodule') . '/awesomeness',
diff --git a/wysiwyg.module b/wysiwyg.module
index aba3920..a4669c0 100644
--- a/wysiwyg.module
+++ b/wysiwyg.module
@@ -502,6 +502,8 @@ function wysiwyg_add_plugin_settings($profile) {
       // Only keep native plugins that are enabled in this profile.
       if (isset($profile->settings['buttons'][$plugin])) {
         $profile_plugins_native[$plugin] = $meta;
+        // Load attached files needed before the plugin script.
+        wysiwyg_process_attached($meta);
       }
     }
     // Invoke the editor's plugin settings callback, so it can populate the
@@ -523,6 +525,8 @@ function wysiwyg_add_plugin_settings($profile) {
         // statically to pass it to the editor's proxy plugin settings callback.
         if (!isset($processed_plugins[$proxy][$plugin])) {
           $profile_plugins_drupal[$plugin] = $processed_plugins[$proxy][$plugin] = $meta;
+          // Load attached files needed before the plugin script.
+          wysiwyg_process_attached($meta);
           // Load the Drupal plugin's JavaScript.
           drupal_add_js($meta['js path'] . '/' . $meta['js file']);
           // Add plugin-specific settings.
@@ -546,6 +550,90 @@ function wysiwyg_add_plugin_settings($profile) {
 }
 
 /**
+ * Adds plugin attachements to a render() structure.
+ *
+ * Works like drupal_process_attached() but uses 'attached files' instead of
+ * the '#attached' property.
+ *
+ * @param $meta
+ *   A meta data structure optionally containing an 'attached files' property.
+ *
+ * @ return
+ *   The return value from drupal_process_attached().
+ *
+ * @see drupal_process_attached()
+ */
+function wysiwyg_process_attached($meta) {
+  if (empty($meta['attached files'])) {
+    return TRUE;
+  }
+  $attached_files = $meta['attached files'];
+  if (!empty($attached_files['js'])) {
+    // As a transitional step between using drupal_add_js() and the
+    // 'attached files' list in plugin hooks, Wysiwyg allows using both
+    // methods to include additional files with a plugin. Settings must
+    // be filtered to avoid the same values being merged in twice and
+    // thus appended again to arrays with numerical keys.
+    $existing_js = drupal_add_js();
+    foreach ($attached_files['js'] as $attached_index => $attached) {
+      if ($attached['type'] != 'setting') {
+        continue;
+      }
+      foreach ($existing_js['settings']['data'] as $existing_setting) {
+        if(wysiwyg_array_intersect_recursive($attached['data'], $existing_setting) == $attached['data']) {
+          // Ignore the setting supplied via 'attached files' since it
+          // exactly matched what was already added via drupal_add_js().
+          unset($attached_files['js'][$attached_index]);
+        }
+      }
+    }
+    if (empty($attached_files['js'])) {
+      unset($attached_files['js']);
+    }
+  }
+  if (!empty($attached_files)) {
+    $element = array(
+      '#attached' => $attached_files,
+    );
+    return drupal_process_attached($element);
+  }
+}
+
+/**
+ * Like array_intersect, but recursive.
+ *
+ * Limited to comparing two arrays.
+ *
+ * @param $array1
+ *   The array with master values to check.
+ *
+ * @param $array2
+ *   An array to compare values against.
+ *
+ * @return
+ *   Returns an array containing all of the values in $array1 whose values
+ *   exist in $array2.
+ *
+ * @see http://php.net/manual/en/function.array-intersect.php
+ */
+function wysiwyg_array_intersect_recursive($array1, $array2) {
+  foreach($array1 as $key => $value) {
+    if (!isset($array2[$key])) {
+      unset($array1[$key]);
+    }
+    else {
+      if (is_array($array1[$key])) {
+        $array1[$key] = wysiwyg_array_intersect_recursive($array1[$key], $array2[$key]);
+      }
+      elseif ($array2[$key] !== $value) {
+        unset($array1[$key]);
+      }
+    }
+  }
+  return $array1;
+}
+
+/**
  * Retrieve available themes for an editor.
  *
  * Editor themes control the visual presentation of an editor.
