diff --git a/filter_example/filter_example.info.yml b/filter_example/filter_example.info.yml
new file mode 100644
index 0000000..5002d67
--- /dev/null
+++ b/filter_example/filter_example.info.yml
@@ -0,0 +1,5 @@
+name: Filter example
+type: module
+description: 'An example module showing how to define a custom filter.'
+package: Example modules
+core: 8.x
diff --git a/filter_example/filter_example.links.menu.yml b/filter_example/filter_example.links.menu.yml
new file mode 100644
index 0000000..d523424
--- /dev/null
+++ b/filter_example/filter_example.links.menu.yml
@@ -0,0 +1,4 @@
+filter_example.page:
+  title: Filter Example
+  route_name: filter_example.page
+  expanded: TRUE
\ No newline at end of file
diff --git a/filter_example/filter_example.module b/filter_example/filter_example.module
new file mode 100644
index 0000000..e69de29
diff --git a/filter_example/filter_example.routing.yml b/filter_example/filter_example.routing.yml
new file mode 100644
index 0000000..0bb8d39
--- /dev/null
+++ b/filter_example/filter_example.routing.yml
@@ -0,0 +1,7 @@
+filter_example.page:
+  path: 'examples/filter-example'
+  defaults:
+    _controller: '\Drupal\filter_example\Controller\FilterExampleController::getContent'
+    _title: 'Filter Example'
+  requirements:
+    _permission: 'access content'
diff --git a/filter_example/src/Controller/FilterExampleController.php b/filter_example/src/Controller/FilterExampleController.php
new file mode 100644
index 0000000..97954a7
--- /dev/null
+++ b/filter_example/src/Controller/FilterExampleController.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Drupal\filter_example\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Url;
+
+/**
+ * Controller routines for Theme example routes.
+ */
+class FilterExampleController extends ControllerBase
+{
+
+  /**
+   * Constructs a simple page.
+   *
+   */
+  public function getContent()
+  {
+
+    return array(
+      '#markup' => '<p>' . $this->t('This example provides two filters.') . '</p><p>' . $this->t('Foo Filter replaces "foo" with a configurable replacement.') . '</p><p>' . $this->t('Time Tag replaces the string
+    "&lt;time /&gt;" with the current time.') . '</p><p>' . $this->t('To use these filters, go to <a href=":link">admin/config/content/formats</a> and
+    configure an input format, or create a new one.', array(':link' => Url::fromRoute('filter.admin_overview')->toString())) . '</p>'
+    );
+  }
+
+}
+
diff --git a/filter_example/src/Plugin/Filter/FilterFoo.php b/filter_example/src/Plugin/Filter/FilterFoo.php
new file mode 100644
index 0000000..4908bd0
--- /dev/null
+++ b/filter_example/src/Plugin/Filter/FilterFoo.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\filter_example\Plugin\Filter;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\filter\FilterProcessResult;
+use Drupal\filter\Plugin\FilterBase;
+
+/**
+ * Provides a filter to replace "foo".
+ *
+ * When used in combination with the filter_align filter, this must run last.
+ *
+ * @Filter(
+ *   id = "filter_foo",
+ *   title = @Translation("Foo Filter (example)"),
+ *   description = @Translation("Every instance of 'foo' in the input text will be replaced with a preconfigured replacement."),
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE,
+ *   settings = {
+ *     "filter_example_foo" = "bar"
+ *   }
+ * )
+ */
+class FilterFoo extends FilterBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form['filter_example_foo'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Substitution string'),
+      '#default_value' => $this->settings['filter_example_foo'],
+      '#description' => $this->t('The string to substitute for "foo" everywhere in the text.'),
+    ];
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process($text, $langcode) {
+    $replace = $this->settings['filter_example_foo'];
+    $new_text = str_replace('foo', $replace, $text);
+    return new FilterProcessResult($new_text);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function tips($long = FALSE) {
+    $replacement = $this->settings['filter_example_foo'];
+    if (!$long) {
+      // This string will be shown in the content add/edit form.
+      return $this->t('<em>foo</em> replaced with %replacement.', array('%replacement' => $replacement));
+    }
+    else {
+      return $this->t('Every instance of "foo" in the input text will be replaced with a configurable value. You can configure this value and put whatever you want there. The replacement value is "%replacement".', array('%replacement' => $replacement));
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/filter_example/src/Plugin/Filter/FilterTime.php b/filter_example/src/Plugin/Filter/FilterTime.php
new file mode 100644
index 0000000..8947700
--- /dev/null
+++ b/filter_example/src/Plugin/Filter/FilterTime.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\filter_example\Plugin\Filter;
+
+use Drupal\filter\Plugin\FilterBase;
+use Drupal\filter\FilterProcessResult;
+
+/**
+ * Provides a filter to replace "foo".
+ *
+ * When used in combination with the filter_align filter, this must run last.
+ *
+ * @Filter(
+ *   id = "filter_time",
+ *   title = @Translation("Time Tag (example)"),
+ *   description = @Translation("Every instance of the special &lt;time /&gt; tag will be replaced with the current date and time in the user's specified time zone."),
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_MARKUP_LANGUAGE,
+ * )
+ */
+class FilterTime extends FilterBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepare($text, $langcode) {
+    return preg_replace('!&lt;time ?/&gt;!', '[filter-example-time]', $text);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process($text, $langcode) {
+    $new_text = str_replace('[filter-example-time]', '<em>' . format_date(time()) . '</em>', $text);
+    return new FilterProcessResult($new_text);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function tips($long = FALSE) {
+    return $this->t('<em>&lt;time /&gt;</em> is replaced with the current time.');
+  }
+
+}
\ No newline at end of file
diff --git a/filter_example/tests/src/Functional/FilterExampleTest.php b/filter_example/tests/src/Functional/FilterExampleTest.php
new file mode 100644
index 0000000..e69de29
