Problem/Motivation

When creating an initial Draft in a new translation, it's not saving as the default revision, which means that node_field_data isn't being populated for that language. This leads to issues with Drupal views.

Steps to reproduce

  • Install Drupal 11.2.x
  • Enable the modules Content Translation, Content Moderation.
  • Assign the Editorial workflow to the Basic page content type.
  • Enable Translations on the Basic Page content type.
  • Add a second language, I'm using Japanese.
  • Create a published version of an English page.
  • Create a draft version of that same page in Japanese.

Here are the issues:

  • on /admin/content, only the English translation shows up
  • on /admin/content/moderated, the Japanese translation shows up correctly, but the Content type field is empty

If you publish the Japanese page, and then set it back to draft, both the issues above are solved.

Proposed resolution

Consider updating the default revision when a new translation draft is first created. We update the default revision when a new entity is created, so it's similar behaviour to get translations to function in the same way.

Issue fork drupal-3088790

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

zolt_toth created an issue. See original summary.

zolt_toth’s picture

I have tried the very same process without the content moderation and workflow modules being enabled. In this case the node_field_data table will contain all needed values, and the sample view will be able to list all node revisions, so maybe the problem is in the content moderation module.

zolt_toth’s picture

Component: language system » content_moderation.module
zolt_toth’s picture

The Drupal\Core\Entity\Sql\SqlContentEntityStorage.php should update the node_field_data table on the line 967. It works like this: removes all records for the given nid and creates new ones for each available language versions. But this line will not be reached, since the newly created revision will not be considered as "default revision", and this line is in a code block with such condition. As far, as I have seen, the content moderation module sets somehow this "default revision" value, and this is the cause of the inconsistent database state. I would appreciate if someone from the module developers would be as kind as to look into this issue. I need a quick solution, so I am going to insert the missing node_field_data record with a post save hook, but this does not seem to be a nice method. I think it is a critical bug, since some other modules (in my case the views module) joins the node values via the node_field_data table expecting that all language versions of a node has a record in this table.

zolt_toth’s picture

I have solved my problem somehow, but because of the Drupal transaction handling it is quite painful... When you get any usable event, you cannot check the existence of the node_field_data record, because it will be inserted by the Drupal transaction handling later. In an entity_translation_insert hook I register a shutdown function (register_shutdown_function), and when that is called I check the existence of the node_field_data record of the inserted translation, and if it fails, check the existence of the node_field_revision record with the given translation language, too (it is to check if the revision actually has been successfully created + I copy all relevant data from the resulting node_field_revision record to the node_field_data table). I will try to change the title of this issue for something more eye-catching, because executing simple foolproof operations an inconsistent database status can be achieved.

zolt_toth’s picture

Title: Moderation/translation problem in a multilang environment » Inconsistent database because of a bug in the Content Moderation module
sergiuteaca’s picture

I have the same problem.
One of the downsides of this bug is that the Delete button is not available for the draft translation.

@zolt_toth I have found another workaround.
The default_revision is overridden in ModerationStateConstraintValidator.php, where it takes the configuration set in the current Workflow. If you edit the configuration file for that workflow by setting default_revision to TRUE for Draft state and import the configuration then there will be created a node_field_data entry for all draft translations in that workflow.
And no code changes will be needed.

I also found this thread for UI code/UI changes that will have the same effect.

sam152’s picture

Issue tags: -moderation multilang translation +content moderation multilingual bug
bahuma20’s picture

Version: 8.7.8 » 9.1.x-dev

Pushing the version to 9.1.x-dev as it still exists so this issue doesn't get lost.

bahuma20’s picture

StatusFileSize
new1.16 KB

I've found out that this could be fixed in the \Drupal\content_moderation\EntityOperations::entityPresave() method.
There is determined if a revision should be set as default revision.

We should treat new translations as if they were new nodes and therefore set them as default revision when they are created.

I've attached a patch that does this.

bahuma20’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 10: 3088790-10.patch, failed testing. View results

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

joachim’s picture

I think we saw this on our site, though we didn't figure out how to reproduce it.

The problem in our DB was that the most recent vid of the node was missing one of its rows. It should have a row for each language, but was missing Chinese. However, older vids did have Chinese translations.

So the translations tab presumably queries for the latest revision, and then looks to see which languages this has. It finds no Chinese – therefore, it shows no Chinese translation.

But when you go to add a Chinese translation, the node form queries for the most recent revision in Chinese, and finds one. So the form contains field values which are already translated.

Saving the node in Chinese creates a new revision across all languages (with the unaffected languages simple copies, AFAIK), and so then the problem is fixed.

rp7’s picture

I can reproduce this issue. The (draft) translation is not available in the node_field_data table and this results the translation is not returned in, for example, $node->getTranslation('hu') or $node->getTranslationLanguages().

To reproduce this programmatically:

/** @var \Drupal\node\NodeInterface $node */
$node = \Drupal::entityTypeManager()
  ->getStorage('node')
  ->create([
    'type' => 'article',
    'langcode' => 'en',
    'title' => 'English',
    'moderation_state' => 'published',
  ]);
$node->save();

$translation = $node->addTranslation('hu', [
  'type' => 'article',
  'title' => 'Hungarian',
  'moderation_state' => 'draft',
]);
$translation->save();
kunalkursija’s picture

@bahuma20 - I think marking revisions as 'default' only makes sense for 'published' and 'archived' states and they make node status 1 & 0 respectively(i.e: Just what the default editorial workflow does).

With patch in #10, No doubt an entry to 'node_field_data' is made. But one problem I noticed after applying the patch was we are losing access to the 'latest version' tab for the newly created translations.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andrew answer’s picture

The #10 patch is good for a new drafts; but we need to fix existing drafts (without publishing, which is not always possible, because of draft can be still in 'approval' phase).

The only way I found is set all Drafts to Archived state and back; this works because it creates default revisions in workflow.

gung wang’s picture

This patch is working on my site (Drupal 9.2.18).

However, there is another issue about the "Draft" of French translation:
- the orphan data (fr) is still in the table node_field_revision after I deleted the translation of French (fr)
- See queries:

mysql> select nid, vid, type, langcode as lang, default_langcode as d_lang, title
    -> from node_field_data
    -> where nid=199155 and langcode='fr';
Empty set (0.00 sec)

mysql> select nid, vid, langcode as lang, default_langcode as d_lang, title
    -> from node_field_revision  
    -> where nid=199155 and langcode='fr';
+--------+--------+------+--------+-------------------+
| nid    | vid    | lang | d_lang | title             |
+--------+--------+------+--------+-------------------+
| 199155 | 768096 | fr   |      0 | Gung test2 French |
+--------+--------+------+--------+-------------------+
1 row in set (0.00 sec)

I applied this patch (https://www.drupal.org/project/drupal/issues/2815779), but it seems not working. The orphaned translation (Draft) is still in the table node_field_revision

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

seanb’s picture

#10 solved my issues in content revision views (for example, we can now show the node type for translations created as a draft).

Regarding #17

But one problem I noticed after applying the patch was we are losing access to the 'latest version' tab for the newly created translations.

Since the translation has never been published, having a "latest version" tab for the new translation wouldn't make sense from my perspective. When creating a new node as a draft (not a translation), we also don't show the "latest version" tab. The latest version only makes sense to me when there is a published / unpublished version to compare it to.

Looking at the failing tests, all fails seem to be testing behaviour that feels "broken". So +1 for this change from me.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

eduardo morales alberti’s picture

+1 to this, but it should treat the translations that already have the draft version but do not have a default revision.

anchal_gupta’s picture

StatusFileSize
new1.16 KB

Rerolled patch #10 against 10.1x.

eduardo morales alberti’s picture

Tests were reviewed.

phot0x_sami_m’s picture

Hello, just ran into this issue! Wondering if there is any update or fix fix planned for this still as I think it's a pretty breaking change - I can help resolve the issue but do we know what is causing it?

dabblela’s picture

I had implemented this same fix (in a slightly different way) and it was causing data loss so I want to caution everyone against using the patches here.

Steps to reproduce:

- Installation of Drupal this patch + content moderation and moderation/translation enabled on a content type
- Enable two languages (Spanish and French)
- Create a published node in English
- Create a published translation in Spanish
- Save a draft of the Spanish translation
- Create a new draft translation in French

The default Spanish translation is actually deleted from node_field_data, so if you visit the published Spanish page you'll get the English version, and if you visit the revisions page for Spanish you will get the English revisions.

Setting the default translation causes this bit of code to fire in \Drupal\Core\Entity\Sql\SqlContentEntityStorage::saveToSharedTables:

// Delete and insert to handle removed values.
      $this->database->delete($table_name)
        ->condition($key, $value)
        ->execute();

which actually deletes all of the node's records from the node_field_data. They're supposed to be repopulated by $node->save(), however when a node is saved from the add translation form it only has the source and new translation languages so the table never gets fully repopulated.

dabblela’s picture

Following up on #29, I created #3329066: Creating a new translation may delete translations with drafts with some more information. The data loss actually comes from a core issue, but this patch makes it more likely to happen.

fathima.asmat’s picture

Patch 6 works for new translations but does not affect existing draft translation that should be treated as default revision when there isn't a published translation. So we may need something like:

      // Check if any of the translation revision has a published version,
      // otherwise set the latest translation to default revision.
      if (!$update_default_revision && $entity instanceof TranslatableInterface && $entity instanceof RevisionableInterface) {
        $update_default_revision = $entity->isNewTranslation();
        if (!$update_default_revision) {
          $update_default_translation_revision = FALSE;
          $published_translation_revision = FALSE;
          $langcode = $this->languageManager->getCurrentLanguage()->getId();
          $storage = $this->entityTypeManager
            ->getStorage($entity->getEntityTypeId());
          $revision_ids = $storage->revisionIds($entity);
          if ($revision_ids) {
            foreach ($revision_ids as $revision_id) {
              $revision = $storage->loadRevision($revision_id);
              if ($revision->hasTranslation($langcode) && ($translation = $revision->getTranslation($langcode)) && $translation->isRevisionTranslationAffected()) {
                if ($workflow->getTypePlugin()
                  ->getState($translation->moderation_state->value)
                  ->isPublishedState()) {
                  $published_translation_revision = TRUE;
                  break;
                }
              }
            }
          }

          if (!$published_translation_revision && $entity->hasTranslation($langcode) && $translation = $entity->getTranslation($langcode)) {
            $update_default_translation_revision = !($workflow->getTypePlugin()
              ->getState($translation->moderation_state->value)
              ->isPublishedState());
          }

          $update_default_revision = $update_default_translation_revision;
        }
      }

Patch attached.

fathima.asmat’s picture

Version: 10.1.x-dev » 9.4.x-dev
Status: Needs work » Needs review

Status: Needs review » Needs work
dabblela’s picture

Agreed with @fathima.asmat, this definitely needs a way to update the default revision of a translation that has never been published. I think it can be done with this code, but I'm a little wary of potentially looping through every revision of a node so I took a different approach.

I was able to fix the issue here by:
1) applying the patch from #3150294: New translations for moderated nodes are not created in the initial workflow state
2) setting the default moderation state to "Default moderation state" and
3) creating a new state called "Pre-published" with "Default revision" enabled

This approach has worked better in testing with modules that use `hasTranslationChanges` (eg, paragraphs), I think because the default revision field is set earlier in the entity save process.

mibfire’s picture

https://www.drupal.org/project/drupal/issues/3088790#comment-14937914

This patch doesn't work in the following case:

  • Content moderation with https://www.drupal.org/files/issues/2023-02-23/content-moderation-unpubl... and moderation/translation enabled on a content type.
  • Enable Croatian language.
  • Create a Draft node in Croatian.
  • Translate this node to English(Draft).
  • Submit the Croatian translation into Published state.
  • Submit the Croatian translation into Unpublished state.
  • Check the node view page of Croatian translation where the "Latest version" tab should be visible(but it is not because the default revision is always the last revision).

However this scenario works with https://www.drupal.org/files/issues/2020-06-09/3088790-10.patch and https://www.drupal.org/project/drupal/issues/3329066#comment-14962117 patches. Plus this works with https://www.drupal.org/project/drupal/issues/3088790#comment-14839675 too.

Version: 9.4.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

v.dovhaliuk’s picture

Issue tags: -
StatusFileSize
new4.69 KB
new4.81 KB

A new patch resolves an issue if Content Moderation is enabled for the Taxonomy, and $revision_ids = $storage->revisionIds($entity); throws an error undefined method <code>revisionIds()

thomwilhelm made their first commit to this issue’s fork.

thomwilhelm’s picture

OK so I ran into this issue recently, clearly translations + content moderation is a very complicated subject in Drupal, but I thought it would just be worth doing a bit of research into why this happens now.

So I'm working on a site that uses translations + the old workbench moderation module, and have been looking into migrating to content moderation. Everything went pretty well, but some of our internal Functional tests were broken in a strange way. Namely the following case (basically comment #16 on this ticket):

  1. Create a published version of an English page.
  2. Create a draft version of that page in Japanese.

Now when you go to any view that relies on node_field_data, the Japanese version of the page isn't there. In our case this mean it wasn't appearing on both /admin/content and a custom view we'd built to show pages that were "Draft content".

I started digging into whether this was an issue on Vanilla Drupal 11 and I found that is it. The draft version of the Japanese page doesn't appear at all on /admin/content, and while it does appear on the view of moderated content /admin/content/moderated, it's Content type field is empty.

Basically a new entity will be saved as the default revision (even being created in draft), but a new translation will not. This is due to the logic that's in content_moderation/src/EntityOperations::preSave:

$update_default_revision = $entity->isNew()
  || $current_state->isDefaultRevisionState()
  || !$this->moderationInfo->isDefaultRevisionPublished($entity);

If you review isDefaultRevisionPublished, in content moderation this returns true if any of the translations are published (which in this case, the English translation is published) so this returns TRUE. Whereas in workbench moderation it was only checking if the translation language was published (which in this case would have been Japanese) so this returns FALSE.

As content moderation forked workbench moderation, you can see this behaviour diverged in core here: https://www.drupal.org/project/drupal/issues/2862988

In that issue, if you read comment #13 and #14 you can see basically the same issue we are experiencing now was discovered, and the following fix was added:

       $update_default_revision = $entity->isNew()
+        || $entity->isNewTranslation()
         || $current_state->isDefaultRevisionState()
         || !$this->isDefaultRevisionPublished($entity, $workflow);

Which is interesting as that's basically the same logic this issue has landed on. So when this this get removed?

This $entity->isNewTranslation() line was then removed as part of the following issue: https://www.drupal.org/project/drupal/issues/2860097

To try and move this forward, I've rebased the MR created by @EduardoMoralesAlberti onto a new MR targeting Drupal 11.x, added some extra test cases to the Content type label not appearing in the moderated content view, and made an attempt to fix up any behaviour that this changes (note: it's still marked as failing, but I believe that's due to unrelated issues in CI).

I'd welcome any feedback from anyone more familiar with translations / content moderation.

thomwilhelm’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update

Haven't reviewed yet but issue summary should follow the standard template please. Current steps are saying install Drupal 8.7.8 so definitely out of date.

Thanks!

thomwilhelm’s picture

Title: Inconsistent database because of a bug in the Content Moderation module » Creating a new translation draft is not populating node_field_data leading to inconsistent data display.
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs issue summary update

Creating a new up to date issue summary with a clear test case.

thomwilhelm changed the visibility of the branch 3088790-inconsistent-database-because to hidden.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs subsystem maintainer review

This will need a rebase.

Am going to voice a concern though that all the test updates make me nervous. That may they were updated just to get to green but could be causing a regression

Would like sub-maintainer review of this eventually.

Thanks!

thomwilhelm’s picture

Status: Needs work » Needs review

Branch is up to date against the latest main. Pipeline failed but I believe that's unrelated to these changes.

Agree ideally we wouldn't be changing tests, however the proposed change in this issue required the changes that were made.

mahde’s picture

I am facing similar issue and not sure if it's related.
Steps to reproduce:

  • Install Drupal 11.2.x
  • Enable the modules Content Translation, Content Moderation.
  • Enable Translations on the Basic Page content type.
  • Add a second language, I'm using French.
  • Create a published version of an English page.
  • Create a draft version of an English page.
  • Create a draft version of that same page in French.

When creating the French draft, I see the field values from the Draft version ff the English page instead of the Published English version.
Then, If I deleted the French draft page and add it again it works fine and pull data from the published English.
Also, I have noticed that the French revisions are having the wrong moderation state in the revision list and all of them are showing published.
Also, if I delete the translation and add it again, I keep see the old (deleted) revisions for French translation in the revisions list.