diff --git a/src/EntityOperations.php b/src/EntityOperations.php
index ed608be..677348d 100644
--- a/src/EntityOperations.php
+++ b/src/EntityOperations.php
@@ -41,6 +41,11 @@ class EntityOperations {
   protected $formBuilder;
 
   /**
+   * @var \Drupal\workbench_moderation\RevisionTrackerInterface
+   */
+  protected $tracker;
+
+  /**
    * Constructs a new EntityOperations object.
    *
    * @param \Drupal\workbench_moderation\ModerationInformationInterface $moderation_info
@@ -51,12 +56,15 @@ class EntityOperations {
    *   The form builder.
    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
    *   The event dispatcher.
+   * @param \Drupal\workbench_moderation\RevisionTrackerInterface $tracker
+   *   The revision tracker.
    */
-  public function __construct(ModerationInformationInterface $moderation_info, EntityTypeManagerInterface $entity_type_manager, FormBuilderInterface $form_builder, EventDispatcherInterface $event_dispatcher) {
+  public function __construct(ModerationInformationInterface $moderation_info, EntityTypeManagerInterface $entity_type_manager, FormBuilderInterface $form_builder, EventDispatcherInterface $event_dispatcher, RevisionTrackerInterface $tracker) {
     $this->moderationInfo = $moderation_info;
     $this->entityTypeManager = $entity_type_manager;
     $this->eventDispatcher = $event_dispatcher;
     $this->formBuilder = $form_builder;
+    $this->tracker = $tracker;
   }
 
   /**
@@ -125,24 +133,69 @@ class EntityOperations {
    *   The entity being saved.
    */
   public function entityPresave(EntityInterface $entity) {
-    if ($entity instanceof ContentEntityInterface && $this->moderationInfo->isModeratableEntity($entity)) {
-      // @todo write a test for this.
-      if ($entity->moderation_state->entity) {
-        $published_state = $entity->moderation_state->entity->isPublishedState();
-
-        // This entity is default if it is new, the default revision, or the
-        // default revision is not published.
-        $update_default_revision = $entity->isNew()
-          || $entity->moderation_state->entity->isDefaultRevisionState()
-          || !$this->isDefaultRevisionPublished($entity);
-
-        $this->entityTypeManager->getHandler($entity->getEntityTypeId(), 'moderation')->onPresave($entity, $update_default_revision, $published_state);
-        $event = new WorkbenchModerationTransitionEvent($entity, isset($entity->original) ? $entity->original->moderation_state->target_id : NULL, $entity->moderation_state->target_id);
-        $this->eventDispatcher->dispatch(WorkbenchModerationEvents::STATE_TRANSITION, $event);
-      }
+    if (!$this->moderationInfo->isModeratableEntity($entity)) {
+      return;
+    }
+
+    /** @var ContentEntityInterface $entity */
+
+    if ($entity->moderation_state->entity) {
+      $published_state = $entity->moderation_state->entity->isPublishedState();
+
+      // This entity is default if it is new, the default revision, or the
+      // default revision is not published.
+      $update_default_revision = $entity->isNew()
+        || $entity->moderation_state->entity->isDefaultRevisionState()
+        || !$this->isDefaultRevisionPublished($entity);
+
+      // Fire per-entity-type logic for handling the save process.
+      $this->entityTypeManager->getHandler($entity->getEntityTypeId(), 'moderation')->onPresave($entity, $update_default_revision, $published_state);
+
+      // Allow other modules to respond to the transition. Note that this
+      // does not provide any mechanism to cancel the transition, since
+      // Entity API doesn't allow hook_entity_presave to short-circuit a save.
+      $event = new WorkbenchModerationTransitionEvent($entity, isset($entity->original) ? $entity->original->moderation_state->target_id : NULL, $entity->moderation_state->target_id);
+      $this->eventDispatcher->dispatch(WorkbenchModerationEvents::STATE_TRANSITION, $event);
+    }
+  }
+
+  /**
+   * Hook bridge.
+   *
+   * @see hook_entity_insert().
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity that was just saved.
+   */
+  public function entityInsert(EntityInterface $entity) {
+    if (!$this->moderationInfo->isModeratableEntity($entity)) {
+      return;
     }
+
+    /** ContentEntityInterface $entity */
+
+    // Update our own record keeping.
+    $this->tracker->setLatestRevision($entity->getEntityTypeId(), $entity->id(), $entity->language()->getId(), $entity->getRevisionId());
   }
 
+  /**
+   * Hook bridge.
+   *
+   * @see hook_entity_update().
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity that was just saved.
+   */
+  public function entityUpdate(EntityInterface $entity) {
+    if (!$this->moderationInfo->isModeratableEntity($entity)) {
+      return;
+    }
+
+    /** ContentEntityInterface $entity */
+
+    // Update our own record keeping.
+    $this->tracker->setLatestRevision($entity->getEntityTypeId(), $entity->id(), $entity->language()->getId(), $entity->getRevisionId());
+  }
 
   /**
    * Act on entities being assembled before rendering.
diff --git a/src/Plugin/views/filter/LatestRevision.php b/src/Plugin/views/filter/LatestRevision.php
new file mode 100644
index 0000000..0812af6
--- /dev/null
+++ b/src/Plugin/views/filter/LatestRevision.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\workbench_moderation\Plugin\views\filter;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\views\Annotation\ViewsFilter;
+use Drupal\views\Plugin\views\filter\FilterPluginBase;
+use Drupal\views\Plugin\views\query\Sql;
+use Drupal\views\Plugin\ViewsHandlerManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Filter to show only the latest revision of an entity.
+ *
+ * @ingroup views_filter_handlers
+ *
+ * @ViewsFilter("latest_revision")
+ */
+class LatestRevision extends FilterPluginBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * @var \Drupal\views\Plugin\ViewsHandlerManager
+   */
+  protected $joinHandler;
+
+  /**
+   * Constructs a new LatestRevision.
+   *
+   * @param array $configuration
+   * @param string $plugin_id
+   * @param mixed $plugin_definition
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, ViewsHandlerManager $join_handler) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->entityTypeManager = $entity_type_manager;
+    $this->joinHandler = $join_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration, $plugin_id, $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('plugin.manager.views.join')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function adminSummary() { }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function operatorForm(&$form, FormStateInterface $form_state) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function canExpose() { return FALSE; }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $table = $this->ensureMyTable();
+
+    /** @var Sql $query */
+    $query = $this->query;
+
+    $definition = $this->entityTypeManager->getDefinition($this->getEntityType());
+    $keys = $definition->getKeys();
+
+    $definition = [
+      'table' => 'workbench_revision_tracker',
+      'type' => 'INNER',
+      'field' => 'entity_id',
+      'left_table' => $table,
+      'left_field' => $keys['id'],
+      'extra' => [
+        ['left_field' => $keys['langcode'], 'field' => 'langcode'],
+        ['left_field' => $keys['revision'], 'field' => 'revision_id'],
+        ['field' => 'entity_type', 'value' => $this->getEntityType()],
+      ],
+    ];
+
+    $join = $this->joinHandler->createInstance('standard', $definition);
+
+    $query->ensureTable('workbench_revision_tracker', $this->relationship, $join);
+  }
+}
diff --git a/src/RevisionTracker.php b/src/RevisionTracker.php
new file mode 100644
index 0000000..4e82fab
--- /dev/null
+++ b/src/RevisionTracker.php
@@ -0,0 +1,154 @@
+<?php
+
+
+namespace Drupal\workbench_moderation;
+
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\DatabaseExceptionWrapper;
+use Drupal\Core\Database\SchemaObjectExistsException;
+
+/**
+ * Tracks metadata about revisions across entities.
+ */
+class RevisionTracker implements RevisionTrackerInterface {
+
+  /**
+   * The name of the SQL table we use for tracking.
+   *
+   * @var string
+   */
+  protected $tableName;
+
+  /**
+   * Constructs a new RevisionTracker.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * RevisionTracker constructor.
+   *
+   * @param \Drupal\Core\Database\Connection $connection
+   *   The database connection.
+   * @param string $table
+   *   The table that should be used for tracking.
+   */
+  public function __construct(Connection $connection, $table = 'workbench_revision_tracker') {
+    $this->connection = $connection;
+    $this->tableName = $table;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setLatestRevision($entity_type, $entity_id, $langcode, $revision_id) {
+    try {
+      $this->recordLatestRevision($entity_type, $entity_id, $langcode, $revision_id);
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      $this->ensureTableExists();
+      $this->recordLatestRevision($entity_type, $entity_id, $langcode, $revision_id);
+    }
+
+    return $this;
+  }
+
+  /**
+   * Records the latest revision of a given entity.
+   *
+   * @param $entity_type
+   *   The machine name of the type of entity.
+   * @param $entity_id
+   *   The Entity ID in question.
+   * @param $langcode
+   *   The langcode of the revision we're saving. Each language has its own
+   *   effective tree of entity revisions, so in different languages
+   *   different revisions will be "latest".
+   * @param $revision_id
+   *   The revision ID that is now the latest revision.
+   *
+   * @return int
+   *   One of the valid returns from a merge query's execute method.
+   */
+  protected function recordLatestRevision($entity_type, $entity_id, $langcode, $revision_id) {
+    return $this->connection->merge($this->tableName)
+      ->keys([
+        'entity_type' => $entity_type,
+        'entity_id' => $entity_id,
+        'langcode' => $langcode,
+      ])
+      ->fields([
+        'revision_id' => $revision_id,
+      ])
+      ->execute();
+  }
+
+  /**
+   * Checks if the table exists and create it if not.
+   *
+   * @return bool
+   *   TRUE if the table was created, FALSE otherwise.
+   */
+  protected function ensureTableExists() {
+    try {
+      if (!$this->connection->schema()->tableExists($this->tableName)) {
+        $this->connection->schema()->createTable($this->tableName, $this->schemaDefinition());
+        return TRUE;
+      }
+    }
+    catch (SchemaObjectExistsException $e) {
+      // If another process has already created the table, attempting to
+      // recreate it will throw an exception. In this case just catch the
+      // exception and do nothing.
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Defines the schema for the tracker table.
+   *
+   * @return array
+   *   The schema API definition for the SQL storage table.
+   */
+  protected function schemaDefinition() {
+    $schema = [
+      'description' => 'Tracks the latest revision for any entity',
+      'fields' => [
+        'entity_type' => [
+          'description' => 'The entity type',
+          'type' => 'varchar_ascii',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ],
+        'entity_id' => [
+          'description' => 'The entity ID',
+          'type' => 'int',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => 0,
+        ],
+        'langcode' => [
+          'description' => 'The language of the entity revision',
+          'type' => 'varchar',
+          'length' => 12,
+          'not null' => TRUE,
+          'default' => '',
+        ],
+        'revision_id' => [
+          'description' => 'The latest revision ID for this entity',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+        ],
+      ],
+      'primary key' => ['entity_type', 'entity_id', 'langcode'],
+    ];
+
+    return $schema;
+  }
+
+}
diff --git a/src/RevisionTrackerInterface.php b/src/RevisionTrackerInterface.php
new file mode 100644
index 0000000..6929c67
--- /dev/null
+++ b/src/RevisionTrackerInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\workbench_moderation;
+
+/**
+ * Tracks metadata about revisions across content entities.
+ */
+interface RevisionTrackerInterface {
+
+  /**
+   * Sets the latest revision of a given entity.
+   *
+   * @param $entity_type
+   *   The machine name of the type of entity.
+   * @param $entity_id
+   *   The Entity ID in question.
+   * @param $langcode
+   *   The langcode of the revision we're saving. Each language has its own
+   *   effective tree of entity revisions, so in different languages
+   *   different revisions will be "latest".
+   * @param $revision_id
+   *   The revision ID that is now the latest revision.
+   *
+   * @return static
+   */
+  public function setLatestRevision($entity_type, $entity_id, $langcode, $revision_id);
+}
diff --git a/tests/modules/workbench_moderation_test_views/config/install/views.view.latest.yml b/tests/modules/workbench_moderation_test_views/config/install/views.view.latest.yml
new file mode 100644
index 0000000..a9b1f37
--- /dev/null
+++ b/tests/modules/workbench_moderation_test_views/config/install/views.view.latest.yml
@@ -0,0 +1,399 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - system.menu.main
+  module:
+    - user
+    - workbench_moderation
+id: latest
+label: Latest
+module: views
+description: ''
+tag: ''
+base_table: node_field_revision
+base_field: vid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'view all revisions'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          tags:
+            previous: '‹ Previous'
+            next: 'Next ›'
+            first: '« First'
+            last: 'Last »'
+          quantity: 9
+      style:
+        type: table
+      row:
+        type: fields
+      fields:
+        nid:
+          id: nid
+          table: node_field_revision
+          field: nid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Node ID'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: number_integer
+          settings:
+            thousand_separator: ''
+            prefix_suffix: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: node
+          entity_field: nid
+          plugin_id: field
+        vid:
+          id: vid
+          table: node_field_revision
+          field: vid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Revision ID'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: number_integer
+          settings:
+            thousand_separator: ''
+            prefix_suffix: true
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: node
+          entity_field: vid
+          plugin_id: field
+        title:
+          id: title
+          table: node_field_revision
+          field: title
+          entity_type: node
+          entity_field: title
+          alter:
+            alter_text: false
+            make_link: false
+            absolute: false
+            trim: false
+            word_boundary: false
+            ellipsis: false
+            strip_tags: false
+            html: false
+          hide_empty: false
+          empty_zero: false
+          settings:
+            link_to_entity: false
+          plugin_id: field
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Title
+          exclude: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+        moderation_state:
+          id: moderation_state
+          table: node_field_revision
+          field: moderation_state
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Moderation state'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: target_id
+          type: entity_reference_label
+          settings:
+            link: true
+          group_column: target_id
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          entity_type: node
+          entity_field: moderation_state
+          plugin_id: field
+      filters:
+        latest_revision:
+          id: latest_revision
+          table: node_revision
+          field: latest_revision
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: '='
+          value: ''
+          group: 1
+          exposed: false
+          expose:
+            operator_id: ''
+            label: ''
+            description: ''
+            use_operator: false
+            operator: ''
+            identifier: ''
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: false
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          entity_type: node
+          plugin_id: latest_revision
+      sorts: {  }
+      title: Latest
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      max-age: 0
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: latest
+      menu:
+        type: normal
+        title: Drafts
+        description: ''
+        expanded: false
+        parent: ''
+        weight: 0
+        context: '0'
+        menu_name: main
+    cache_metadata:
+      max-age: 0
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
diff --git a/tests/modules/workbench_moderation_test_views/workbench_moderation_test_views.info.yml b/tests/modules/workbench_moderation_test_views/workbench_moderation_test_views.info.yml
new file mode 100644
index 0000000..b42a345
--- /dev/null
+++ b/tests/modules/workbench_moderation_test_views/workbench_moderation_test_views.info.yml
@@ -0,0 +1,8 @@
+name: 'Workbench moderation test views'
+type: module
+description: 'Provides default views for views Workbench moderation tests.'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+  - workbench_moderation
diff --git a/tests/src/Functional/LatestRevisionViewsFilterTest.php b/tests/src/Functional/LatestRevisionViewsFilterTest.php
new file mode 100644
index 0000000..820fe14
--- /dev/null
+++ b/tests/src/Functional/LatestRevisionViewsFilterTest.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace Drupal\Tests\workbench_moderation\Functional;
+
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+use Drupal\simpletest\BrowserTestBase;
+
+/**
+ * Tests the "Latest Revision" views filter.
+ *
+ * @group workbench_moderation
+ * @runTestsInSeparateProcesses
+ * @preserveGlobalState disabled
+ *
+ */
+class LatestRevisionViewsFilterTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['workbench_moderation_test_views', 'workbench_moderation', 'node', 'views', 'options', 'user', 'system'];
+
+  /**
+   *
+   */
+  public function testViewShowsCorrectNids() {
+    $this->createNodeType('Test', 'test');
+
+    $permissions = [
+      'access content',
+      'view all revisions',
+    ];
+    $editor1 = $this->drupalCreateUser($permissions);
+
+    $this->drupalLogin($editor1);
+
+    // Make a node that is only ever in Draft.
+
+    /** @var Node $node_1 */
+    $node_1 = Node::create([
+      'type' => 'test',
+      'title' => 'Node 1 - Rev 1',
+      'uid' => $editor1->id(),
+    ]);
+    $node_1->moderation_state->target_id = 'draft';
+    $node_1->save();
+
+    // Make a node that is in Draft, then Published.
+
+    /** @var Node $node_2 */
+    $node_2 = Node::create([
+      'type' => 'test',
+      'title' => 'Node 2 - Rev 1',
+      'uid' => $editor1->id(),
+    ]);
+    $node_2->moderation_state->target_id = 'draft';
+    $node_2->save();
+
+    $node_2->setTitle('Node 2 - Rev 2');
+    $node_2->moderation_state->target_id = 'published';
+    $node_2->save();
+
+    // Make a node that is in Draft, then Published, then Draft.
+
+    /** @var Node $node_3 */
+    $node_3 = Node::create([
+      'type' => 'test',
+      'title' => 'Node 3 - Rev 1',
+      'uid' => $editor1->id(),
+    ]);
+    $node_3->moderation_state->target_id = 'draft';
+    $node_3->save();
+
+    $node_3->setTitle('Node 3 - Rev 2');
+    $node_3->moderation_state->target_id = 'published';
+    $node_3->save();
+
+    $node_3->setTitle('Node 3 - Rev 3');
+    $node_3->moderation_state->target_id = 'draft';
+    $node_3->save();
+
+
+    // Now show the View, and confirm that only the correct titles are showing.
+
+    $this->drupalGet('/latest');
+    $page = $this->getSession()->getPage();
+    $this->assertEquals(200, $this->getSession()->getStatusCode());
+    $this->assertTrue($page->hasContent('Node 1 - Rev 1'));
+    $this->assertTrue($page->hasContent('Node 2 - Rev 2'));
+    $this->assertTrue($page->hasContent('Node 3 - Rev 3'));
+    $this->assertFalse($page->hasContent('Node 2 - Rev 1'));
+    $this->assertFalse($page->hasContent('Node 3 - Rev 1'));
+    $this->assertFalse($page->hasContent('Node 3 - Rev 2'));
+  }
+
+  /**
+   * Creates a new node type.
+   *
+   * @param string $label
+   *   The human-readable label of the type to create.
+   * @param string $machine_name
+   *   The machine name of the type to create.
+   */
+  protected function createNodeType($label, $machine_name) {
+    /** @var NodeType $node_type */
+    $node_type = NodeType::create([
+      'type' => $machine_name,
+      'label' => $label,
+    ]);
+    $node_type->setThirdPartySetting('workbench_moderation', 'enabled', TRUE);
+    $node_type->save();
+  }
+}
diff --git a/workbench_moderation.module b/workbench_moderation.module
index 8bd5c44..67d7405 100644
--- a/workbench_moderation.module
+++ b/workbench_moderation.module
@@ -96,6 +96,20 @@ function workbench_moderation_entity_presave(EntityInterface $entity) {
 }
 
 /**
+ * Implements hook_entity_insert().
+ */
+function workbench_moderation_entity_insert(EntityInterface $entity) {
+  return \Drupal::service('workbench_moderation.entity_operations')->entityInsert($entity);
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function workbench_moderation_entity_update(EntityInterface $entity) {
+  return \Drupal::service('workbench_moderation.entity_operations')->entityUpdate($entity);
+}
+
+/**
  * Implements hook_local_tasks_alter().
  */
 function workbench_moderation_local_tasks_alter(&$local_tasks) {
@@ -178,3 +192,25 @@ function workbench_moderation_theme($existing, $type, $theme, $path) {
 
   return $themes;
 }
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function workbench_moderation_views_data_alter(array &$data) {
+
+  /** @var \Drupal\workbench_moderation\ModerationInformationInterface $mod_info */
+  $mod_info = \Drupal::service('workbench_moderation.moderation_information');
+
+  /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $etm */
+  $etm = \Drupal::service('entity_type.manager');
+
+  $revisionable_types = $mod_info->selectRevisionableEntities($etm->getDefinitions());
+
+  foreach ($revisionable_types as $type) {
+    $data[$type->getRevisionTable()]['latest_revision'] = [
+      'title' => t('Is Latest Revision'),
+      'help' => t('Restrict the view to only revisions that are the latest revision of their entity.'),
+      'filter' => ['id' => 'latest_revision'],
+    ];
+  }
+}
diff --git a/workbench_moderation.services.yml b/workbench_moderation.services.yml
index 0edbe42..ecdcdbc 100644
--- a/workbench_moderation.services.yml
+++ b/workbench_moderation.services.yml
@@ -16,7 +16,7 @@ services:
     arguments: ['@string_translation', '@workbench_moderation.moderation_information', '@entity_type.manager']
   workbench_moderation.entity_operations:
     class: Drupal\workbench_moderation\EntityOperations
-    arguments: ['@workbench_moderation.moderation_information', '@entity_type.manager', '@form_builder', '@event_dispatcher']
+    arguments: ['@workbench_moderation.moderation_information', '@entity_type.manager', '@form_builder', '@event_dispatcher', '@workbench_moderation.revision_tracker']
   workbench_moderation.inline_editing_disabler:
     class: \Drupal\workbench_moderation\InlineEditingDisabler
     arguments: ['@workbench_moderation.moderation_information']
@@ -28,3 +28,8 @@ services:
     arguments: ['@workbench_moderation.moderation_information']
     tags:
       - { name: access_check, applies_to: _workbench_moderation_latest_version }
+  workbench_moderation.revision_tracker:
+    class: Drupal\workbench_moderation\RevisionTracker
+    arguments: ['@database']
+    tags:
+     - { name: backend_overridable }
