diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..58ee6a60554b4522d120e4c30805040a1170403c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+.dropwhale
+.idea/
+docker-compose.yml
+dropwhale.settings
+*.patch
+interdiff*.txt
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7ee4fafe85646e2bc5e28f8bf3d6918f20a27796
--- /dev/null
+++ b/README.md
@@ -0,0 +1,73 @@
+# Migrate Process Array
+
+When migrating content, sometimes you have an array of values you need to filter against known items. In PHP, you would use `array_intersect()` or  `array_diff()`. 
+
+This module provides migration process plugins for each:
+
+```yaml
+  field_of_array_values:
+    plugin: array_intersect
+    source: some_array_field
+    match:
+      - values
+      - to
+      - match
+  field_of_array_values:
+    plugin: array_diff
+    source: some_array_field
+    exclude:
+      - values
+      - to
+      - match
+```
+
+For a given field value:
+
+```
+[
+  'a',
+  'bunch',
+  'of',
+  'values',
+];
+```
+
+The `array_intersect` plugin would return:
+
+```
+[
+  'values',
+];
+```
+
+Whereas the `array_diff` plugin would return:
+
+```
+[
+  'a',
+  'bunch',
+  'of',
+];
+```
+
+## Using custom filtering
+
+Sometimes you'd rather write your own custom filer. In PHP, you'd use `array_filter()`, and provide your own custom callback. This module also provides a process plugin:
+
+```
+  field_of_array_values:
+    plugin: array_filter
+    source: some_array_field
+    callable: 'my_function'
+```
+
+The `callable` parameter works just like it does in core's `callback` process plugin. You can specify a static class function like so:
+
+```
+  field_of_array_values:
+    plugin: array_filter
+    source: some_array_field
+    callable:
+      - '\Drupal\my_module\MyClass'
+      - myMethod
+```
diff --git a/README.txt b/README.txt
deleted file mode 100644
index c05cba629d63e1794d95faa736b23e1b59d097a5..0000000000000000000000000000000000000000
--- a/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Migrate Process Array
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..e5ae4348490689c57793c9861e45d7cc36019fbf
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,14 @@
+{
+  "name": "drupal/migrate_process_array",
+  "type": "drupal-module",
+  "description": "Array-centric utilties for Migrations",
+  "keywords": ["Drupal"],
+  "license": "GPL-2.0+",
+  "homepage": "https://www.drupal.org/project/migrate_process_array",
+  "minimum-stability": "dev",
+  "support": {
+    "issues": "https://www.drupal.org/project/issues/migrate_process_array",
+    "source": "http://cgit.drupalcode.org/migrate_process_array"
+  },
+  "require": { }
+}
diff --git a/migrate_process_array.info.yml b/migrate_process_array.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d6d589989c93b7b552dd2d73154b0fe64124753e
--- /dev/null
+++ b/migrate_process_array.info.yml
@@ -0,0 +1,5 @@
+name: 'Migrate Process Array'
+type: module
+description: 'Array-centric utilties for Migrations'
+core: 8.x
+package: 'Migration'
diff --git a/migrate_process_array.module b/migrate_process_array.module
new file mode 100644
index 0000000000000000000000000000000000000000..4a3843da0bf165330883c09604ac9c4c3e688007
--- /dev/null
+++ b/migrate_process_array.module
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains migrate_process_array.module.
+ */
+
+use Drupal\Core\Routing\RouteMatchInterface;
+
+/**
+ * Implements hook_help().
+ */
+function migrate_process_array_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    // Main module help for the migrate_process_array module.
+    case 'help.page.migrate_process_array':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('Array-centric utilties for Migrations') . '</p>';
+      return $output;
+
+    default:
+  }
+}
diff --git a/src/Plugin/migrate/process/ArrayDiff.php b/src/Plugin/migrate/process/ArrayDiff.php
new file mode 100644
index 0000000000000000000000000000000000000000..0af1031d1462c1ae3e545e4ccc5c65c5fb79093f
--- /dev/null
+++ b/src/Plugin/migrate/process/ArrayDiff.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\migrate_process_array\Plugin\migrate\process;
+
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+
+/**
+ * Enables use of array_diff within a migration.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "array_diff"
+ * )
+ */
+class ArrayDiff extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    // Only process non-empty values.
+    if (empty($value)) {
+      return NULL;
+    }
+
+    // The input must be an array.
+    if (!is_array($value)) {
+      $value = [$value];
+    }
+
+    // As well as the array to match against.
+    $exclude = $this->configuration['exclude'];
+    if (!is_array($exclude)) {
+      $exclude = [$exclude];
+    }
+
+    // Get the method and callable, if any.
+    $method = empty($this->configuration['method']) ? '' : $this->configuration['method'];
+    $callable = empty($this->configuration['callable']) ? NULL : $this->configuration['callable'];
+
+    // Return results by method.
+    $out = [];
+    if ($method == 'assoc') {
+      $out = array_diff_assoc($value, $exclude);
+    }
+    elseif ($method == 'key') {
+      $out = array_diff_key($value, $exclude);
+    }
+    elseif ($method == 'uassoc' && !empty($callable)) {
+      $out = array_diff_uassoc($value, $exclude, $callable);
+    }
+    elseif ($method == 'ukey') {
+      $out = array_diff_ukey($value, $exclude, $callable);
+    }
+    else {
+      $out = array_diff($value, $exclude);
+    }
+
+    // Migrate treats NULL as empty not not empty arrays.
+    if (empty($out)) {
+      return NULL;
+    }
+
+    echo "Diff  : ";
+    var_dump($out);
+    return $out;
+  }
+}
diff --git a/src/Plugin/migrate/process/ArrayFilter.php b/src/Plugin/migrate/process/ArrayFilter.php
new file mode 100644
index 0000000000000000000000000000000000000000..8233a197983c7c36e7ac4892f740e9faad41015d
--- /dev/null
+++ b/src/Plugin/migrate/process/ArrayFilter.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\migrate_process_array\Plugin\migrate\process;
+
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+
+/**
+ * Enables use of array_filter within a migration.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "array_filter"
+ * )
+ */
+class ArrayFilter extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    // Only process non-empty values.
+    if (empty($value)) {
+      return NULL;
+    }
+
+    // The input must be an array.
+    if (!is_array($value)) {
+      $value = [$value];
+    }
+
+    // Return using a custom callable, if provided.
+    if (!empty($this->configuration['callable'])) {
+      return array_filter($value, $this->configuration['callable']);
+    }
+
+    // Otherwise, just use the default filter.
+    return array_filter($value);
+  }
+}
diff --git a/src/Plugin/migrate/process/ArrayIntersect.php b/src/Plugin/migrate/process/ArrayIntersect.php
new file mode 100644
index 0000000000000000000000000000000000000000..97f8e5ad88592ce40c55f5180aedf32e5551d422
--- /dev/null
+++ b/src/Plugin/migrate/process/ArrayIntersect.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\migrate_process_array\Plugin\migrate\process;
+
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+
+/**
+ * Enables use of array_intersect within a migration.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "array_intersect"
+ * )
+ */
+class ArrayIntersect extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    // Only process non-empty values.
+    if (empty($value)) {
+      return NULL;
+    }
+
+    // The input must be an array.
+    if (!is_array($value)) {
+      $value = [$value];
+    }
+
+    // As well as the array to match against.
+    $match = $this->configuration['match'];
+    if (!is_array($match)) {
+      $match = [$match];
+    }
+    
+    // Get the method and callable, if any.
+    $method = empty($this->configuration['method']) ? '' : $this->configuration['method'];
+    $callable = empty($this->configuration['callable']) ? NULL : $this->configuration['callable'];
+    
+    // Return results by method.
+    $out = [];
+    if ($method == 'assoc') {
+      $out = array_intersect_assoc($value, $match);
+    }
+    elseif ($method == 'key') {
+      $out = array_intersect_key($value, $match);
+    }
+    elseif ($method == 'uassoc' && !empty($callable)) {
+      $out = array_intersect_uassoc($value, $match, $callable);
+    }
+    elseif ($method == 'ukey') {
+      $out = array_intersect_ukey($value, $match, $callable);
+    }
+    else {
+      $out = array_intersect($value, $match);
+    }
+
+    // Migrate treats NULL as empty not not empty arrays.
+    if (empty($out)) {
+      return NULL;
+    }
+
+    echo "Intersect: ";
+    var_dump($out);
+    return $out;
+  }
+}