diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 5f011c6f98..91cb0929ab 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -10,6 +10,7 @@ use Drupal\Core\Render\Element; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; +use Drupal\node\NodeInterface; use Drupal\taxonomy\Entity\Term; /** @@ -169,20 +170,21 @@ function taxonomy_node_insert(EntityInterface $node) { * The index lists all terms that are related to a given node entity, and is * therefore maintained at the entity level. * - * @param \Drupal\node\Entity\Node $node + * @param \Drupal\node\NodeInterface $node * The node entity. */ -function taxonomy_build_node_index($node) { +function taxonomy_build_node_index(NodeInterface $node) { // We maintain a denormalized table of term/node relationships, containing // only data for current, published nodes. if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityTypeManager()->getStorage('node') instanceof SqlContentEntityStorage)) { return; } - $status = $node->isPublished(); - $sticky = (int) $node->isSticky(); - // We only maintain the taxonomy index for published nodes. - if ($status && $node->isDefaultRevision()) { + // We only maintain the taxonomy index for the default node revision. + if ($node->isDefaultRevision()) { + $status = (int) $node->isPublished(); + $sticky = (int) $node->isSticky(); + // Collect a unique list of all the term IDs from all node fields. $tid_all = []; $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem'; @@ -205,7 +207,7 @@ function taxonomy_build_node_index($node) { $connection = \Drupal::database(); foreach ($tid_all as $tid) { $connection->merge('taxonomy_index') - ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()]) + ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $status]) ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()]) ->execute(); } diff --git a/core/modules/taxonomy/taxonomy.post_update.php b/core/modules/taxonomy/taxonomy.post_update.php index 6b5fefe6d0..493f61fcb8 100644 --- a/core/modules/taxonomy/taxonomy.post_update.php +++ b/core/modules/taxonomy/taxonomy.post_update.php @@ -5,6 +5,9 @@ * Post update functions for Taxonomy. */ +use Drupal\Core\Site\Settings; +use Drupal\node\NodeInterface; + /** * Implements hook_removed_post_updates(). */ @@ -19,3 +22,48 @@ function taxonomy_removed_post_updates() { 'taxonomy_post_update_clear_views_argument_validator_plugins_cache' => '10.0.0', ]; } + +/** + * Add unpublished nodes to the taxonomy index table. + */ +function taxonomy_post_update_add_unpublished_nodes_to_taxonomy_index(&$sandbox) { + $database = \Drupal::database(); + + if (!isset($sandbox['total'])) { + // Initialize state for future calls. + $sandbox['last'] = 0; + $sandbox['count'] = 0; + + $query = $database->select('node_field_data', 'n') + ->condition('n.status', NodeInterface::NOT_PUBLISHED); + $sandbox['total'] = $query->countQuery()->execute()->fetchField(); + } + + if ($sandbox['total']) { + // Operate on every unpublished node, in batches. + $batch_size = Settings::get('entity_update_batch_size', 100); + $query = $database->select('node_field_data', 'n'); + $query->fields('n', ['nid']) + ->condition('n.nid', $sandbox['last'], '>') + ->condition('n.status', NodeInterface::NOT_PUBLISHED) + ->orderBy('n.nid', 'ASC') + ->range(0, $batch_size); + $nids = $query->execute()->fetchCol(); + $node_storage = \Drupal::entityTypeManager()->getStorage('node'); + // Build the taxonomy index for each node. + foreach ($node_storage->loadMultiple($nids) as $node) { + // Delete node index to avoid integrity constraint violation errors. + taxonomy_delete_node_index($node); + taxonomy_build_node_index($node); + $sandbox['last'] = $node->id(); + } + $sandbox['count'] += $batch_size; + } + // Finish after all the unpublished nodes have been processed. + if ($sandbox['count'] < $sandbox['total']) { + $sandbox['#finished'] = FALSE; + } + else { + $sandbox['#finished'] = TRUE; + } +} diff --git a/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php b/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php index c5f7087827..e42730cee3 100644 --- a/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php +++ b/core/modules/taxonomy/tests/src/Functional/TermIndexTest.php @@ -129,6 +129,21 @@ public function testTaxonomyIndex() { ->fetchField(); $this->assertEquals(1, $index_count, 'Term 1 is indexed once.'); + // Check that the node status is stored correctly. + $node_status = (int) $connection->query('SELECT status FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ + ':nid' => $node->id(), + ':tid' => $term_1->id(), + ])->fetchField(); + $this->assertEquals(1, $node_status, 'Term 1 is index once with the node status published.'); + + // Un publish the article, this should update the register. + $node->setUnpublished()->save(); + $node_status = (int) $connection->query('SELECT status FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', [ + ':nid' => $node->id(), + ':tid' => $term_1->id(), + ])->fetchField(); + $this->assertEquals(0, $node_status, 'Term 1 is index once with the node status unpublished.'); + // Update the article to change one term. $edit["{$this->fieldName1}[]"] = $term_2->id(); $this->drupalGet('node/' . $node->id() . '/edit');