diff --git a/core/modules/views/src/Plugin/views/join/JoinPluginBase.php b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
index a0bbedf7315dd95bf08989c9ec8509e1a8ea65ae..6811dcddc78daa3a05dd0355ccd3bd7d4814d841 100644
--- a/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -37,6 +37,30 @@
  * Note that the default join type is a LEFT join when 'type' is not supplied in
  * the join plugin configuration.
  *
+ * If an SQL expression is needed for the first part of the left table join
+ * condition, 'left_formula' can be used instead of 'left_field'.
+ * For this SQL:
+ * @code
+ * LEFT JOIN {two} ON MAX(one.field_a) = two.field_b AND one.field_c = 'some_val'
+ * @endcode
+ * Use this configuration:
+ * @code
+ * $configuration = array(
+ *   'table' => 'two',
+ *   'field' => 'field_b',
+ *   'left_table' => 'one',
+ *   'left_formula' => 'MAX(one.field_a)',
+ *   'operator' => '=',
+ *   'extra' => array(
+ *     0 => array(
+ *       'left_field' => 'field_c',
+ *       'value' => 'some_val',
+ *     ),
+ *   ),
+ * );
+ * $join = Views::pluginManager('join')->createInstance('standard', $configuration);
+ * @endcode
+ *
  * For this SQL:
  * @code
  * INNER JOIN {two} ON one.field_a = two.field_b AND one.field_c = 'some_val'
@@ -156,6 +180,13 @@ class JoinPluginBase extends PluginBase implements JoinPluginInterface {
    */
   public $leftField;
 
+  /**
+   * A formula to be used instead of the left field.
+   *
+   * @var string
+   */
+  public $leftFormula;
+
   /**
    * An array of extra conditions on the join.
    *
@@ -238,6 +269,10 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
     $this->leftField = $configuration['left_field'];
     $this->field = $configuration['field'];
 
+    if (!empty($configuration['left_formula'])) {
+      $this->leftFormula = $configuration['left_formula'];
+    }
+
     if (!empty($configuration['extra'])) {
       $this->extra = $configuration['extra'];
     }
@@ -263,7 +298,7 @@ public function buildJoin($select_query, $table, $view_query) {
 
     if ($this->leftTable) {
       $left_table = $view_query->getTableInfo($this->leftTable);
-      $left_field = "$left_table[alias].$this->leftField";
+      $left_field = $this->leftFormula ?: "$left_table[alias].$this->leftField";
     }
     else {
       // This can be used if left_field is a formula or something. It should be used only *very* rarely.
diff --git a/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php b/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php
index 6a35d5259359cc094f3ef84018cbee321510ca44..bf7042030feca418bf8bad8f029b13a5272e33b6 100644
--- a/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php
+++ b/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php
@@ -202,6 +202,20 @@ public function testBasePlugin() {
     $this->assertTrue(strpos($join_info['condition'], "views_test_data.status = :views_join_condition_5") !== FALSE, 'Make sure the second extra join condition appears in the query.');
     $this->assertTrue(strpos($join_info['condition'], "users5.name = views_test_data.name") !== FALSE, 'Make sure the third extra join condition appears in the query.');
     $this->assertEqual(array_values($join_info['arguments']), ['en', 0], 'Make sure the arguments are in the right order');
+
+    // Test that joins using 'left_formula' are properly built.
+    $configuration['left_formula'] = 'MAX(views_test_data.uid)';
+    $join = $this->manager->createInstance('standard', $configuration);
+    $table = ['alias' => 'users6'];
+    $join->buildJoin($query, $table, $view->query);
+
+    $tables = $query->getTables();
+    $join_info = $tables['users6'];
+    $this->assertTrue(strpos($join_info['condition'], "MAX(views_test_data.uid) = users6.uid") !== FALSE, 'Make sure the join condition appears in the query.');
+    $this->assertTrue(strpos($join_info['condition'], "users6.langcode = :views_join_condition_7") !== FALSE, 'Make sure the first extra join condition appears in the query.');
+    $this->assertTrue(strpos($join_info['condition'], "views_test_data.status = :views_join_condition_8") !== FALSE, 'Make sure the second extra join condition appears in the query.');
+    $this->assertTrue(strpos($join_info['condition'], "users6.name = views_test_data.name") !== FALSE, 'Make sure the third extra join condition appears in the query.');
+    $this->assertEqual(array_values($join_info['arguments']), ['en', 0], 'Make sure the arguments are in the right order');
   }
 
 }
diff --git a/core/modules/workspaces/src/ViewsQueryAlter.php b/core/modules/workspaces/src/ViewsQueryAlter.php
index a6e4e0d528e80f2c18e4c71c8e252fec6adfea24..485f51a81e57a0d2d675a609b74bd508c88f7c95 100644
--- a/core/modules/workspaces/src/ViewsQueryAlter.php
+++ b/core/modules/workspaces/src/ViewsQueryAlter.php
@@ -187,8 +187,7 @@ protected function alterQueryForEntityType(Sql $query, EntityTypeInterface $enti
 
         // Update the join to use our COALESCE.
         $revision_field = $entity_type->getKey('revision');
-        $table_info['join']->leftTable = NULL;
-        $table_info['join']->leftField = "COALESCE($workspace_association_table.target_entity_revision_id, $relationship.$revision_field)";
+        $table_info['join']->leftFormula = "COALESCE($workspace_association_table.target_entity_revision_id, $relationship.$revision_field)";
 
         // Update the join and the table info to our new table name, and to join
         // on the revision key.
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
index 1bb7d2f1096f64a4a275368dfc8c018c376a321d..d57849fbff0ee56b80bd1cce7fa4cec1911011fe 100644
--- a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
@@ -101,8 +101,8 @@ protected function setUp(): void {
     // Create two nodes, a published and an unpublished one, so we can test the
     // behavior of the module with default/existing content.
     $this->createdTimestamp = \Drupal::time()->getRequestTime();
-    $this->nodes[] = $this->createNode(['title' => 'live - 1 - r1 - published', 'created' => $this->createdTimestamp++, 'status' => TRUE]);
-    $this->nodes[] = $this->createNode(['title' => 'live - 2 - r2 - unpublished', 'created' => $this->createdTimestamp++, 'status' => FALSE]);
+    $this->nodes[] = $this->createNode(['title' => 'live - 1 - r1 - published', 'body' => 'node 1', 'created' => $this->createdTimestamp++, 'status' => TRUE]);
+    $this->nodes[] = $this->createNode(['title' => 'live - 2 - r2 - unpublished', 'body' => 'node 2', 'created' => $this->createdTimestamp++, 'status' => FALSE]);
 
     $translation = $this->nodes[0]->addTranslation('de');
     $translation->setTitle('live - 1 - r1 - published - de');
@@ -794,6 +794,23 @@ protected function assertWorkspaceStatus(array $expected, $entity_type_id) {
           $this->assertNoRaw($expected_entity_values[$entity_keys['label']]);
         }
       }
+
+      // Add a filter on a field that is stored in a dedicated table in order to
+      // test field joins with extra conditions (e.g. 'deleted' and 'langcode').
+      $view->destroy();
+      $view->setDisplay('page_1');
+      $filters = $view->displayHandlers->get('page_1')->getOption('filters');
+      $view->displayHandlers->get('page_1')->overrideOption('filters', $filters + [
+        'body_value' => [
+          'id' => 'body_value',
+          'table' => 'node__body',
+          'field' => 'body_value',
+          'operator' => 'not empty',
+          'plugin_id' => 'string',
+        ],
+      ]);
+      $view->execute();
+      $this->assertIdenticalResultset($view, $expected_frontpage, ['nid' => 'nid']);
     }
   }