Content moderation "current revision" not set on nodes migrated from Drupal 7 where there are both a published and draft revisions

Created on 11 August 2020, almost 5 years ago
Updated 19 June 2023, about 2 years ago

I am working on upgrading a Drupal 7 site to Drupal 8. The upgrade uses a content-only custom migration. The Drupal 7 source site and the Drupal 8 destination do not contain any custom modules other than a Drupal 8 custom module containing the custom migration configuration. Both source and destination site were created using the Standard install profile.

I have created migrations for both the node and node revisions of the Page content type. The page node consists of a media reference field and a paragraph reference field. After running the migration I notice that for migrate nodes which had both a published and draft version in which the draft revision is more recent than the published revision then the current content revision is not set.

Here is the moderation tab of such a node in Drupal 7:

Here is the moderation tab of the same node after migrating it to Drupal 8:

Following is the `content_moderation_state_revision` table from the destination database. The node in question is id = 3.

Following is the `content_moderation_state_field_revision` table from the destination database.

Here is the config for the Page node migration:

langcode: en 

status: true 

dependencies: {  } 

id: health_node_standard_page 

label: Standard Page Nodes 

audit: true 

migration_tags: 

  - Drupal 7 

  - Content 

migration_group: health 

deriver: Drupal\node\Plugin\migrate\D7NodeDeriver 

source: 

  plugin: d7_node_extended 

  node_type: page 

process: 

  nid: tnid 

  vid: vid 

  langcode: 

    - 

      plugin: static_map 

      source: language 

      map: 

        und: en 

      bypass: true 

  title: title 

  uid: node_uid 

  status: status 

  created: created 

  changed: changed 

  promote: promote 

  sticky: sticky 

  revision_uid: revision_uid 

  revision_log: log 

  revision_timestamp: timestamp 

  field_h_content_blocks: 

    plugin: sub_process 

    source: field_content_blocks 

    process: 

      paragraphs: 

        plugin: migration_lookup 

        migration: 

          - health_paragraph_content_text 

        source: value 

      target_id: 

        - 

          plugin: extract 

          source: '@paragraphs' 

          index: 

            - 0 

      target_revision_id: 

        - 

          plugin: extract 

          source: '@paragraphs' 

          index: 

            - 1 

  field_h_image_featured: 

    - 

      plugin: sub_process 

      source: field_featured_image 

      process: 

        target_id: 

          - 

            plugin: migration_lookup 

            migration: health_media_image 

            source: fid 

  moderation_state: 

    - 

      plugin: static_map 

      source: moderation_state 

      map: 

        published: published 

        draft: draft 

        needs_review: needs_review 

      default_value: draft 

destination: 

  plugin: entity:node 

  default_bundle: h_standard_page 

migration_dependencies: 

  required: 

    - health_user 

    - health_paragraph_content_text 

    - health_media_image 

Here is the config for the Page node revisions migration:

langcode: en 

status: true 

dependencies: {  } 

id: health_node_revision_standard_page 

label: Node revisions - Standard Page 

audit: true 

migration_tags: 

  - Drupal 7 

  - Content 

migration_group: health 

deriver: Drupal\node\Plugin\migrate\D7NodeDeriver 

source: 

  plugin: d7_node_revision_extended 

process: 

  nid: 

    - 

      plugin: get 

      source: nid 

  vid: 

    - 

      plugin: get 

      source: vid 

  langcode: 

    - 

      plugin: static_map 

      source: language 

      map: 

        und: en 

      bypass: true 

  title: title 

  uid: node_uid 

  status: 

    - 

      plugin: get 

      source: status 

  created: created 

  changed: changed 

  promote: promote 

  sticky: sticky 

  revision_uid: revision_uid 

  revision_log: log 

  revision_timestamp: timestamp 

  moderation_state: 

    - 

      plugin: static_map 

      source: moderation_state 

      map: 

        published: published 

        draft: draft 

        needs_review: needs_review 

      default_value: draft 

destination: 

  plugin: entity_revision:node 

  default_bundle: h_standard_page 

migration_dependencies: 

  required: 

    - health_node_standard_page 

Both migrations make use of a custom "Source" which extends the "d7_node" and "d7_node_revision" source plugins accordingly. These extended source plugins get the moderation state info of the relevant node or node revision.

/**
 * Extended version of core Drupal 7 node source from database.
 *
 * @MigrateSource(
 *   id = "d7_node_extended",
 *   source_module = "node"
 * )
 */
class D7NodeExtended extends Node {

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    // Make the node's moderation state available to migration.
    $database = $this->getDatabase();
    $vid = $row->getSourceProperty('vid');
    $query = $database
      ->select('workbench_moderation_node_history', 'wm')
      ->fields('wm', ['state'])
      ->condition('wm.vid', $vid)
      ->orderBy('wm.stamp', 'DESC')
      ->range(0, 1);
    $value = $query
      ->execute()
      ->fetchField();
    if ($value) {
      $row->setSourceProperty('moderation_state', $value);
    }

    return parent::prepareRow($row);
  }
}
/**
 * Extended version of core Drupal 7 node source from database.
 *
 * @MigrateSource(
 *   id = "d7_node_revision_extended",
 *   source_module = "node"
 * )
 */
class D7NodeRevisionExtended extends NodeRevision {

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    // Make the node revision's moderation state available to migration.
    $database = $this->getDatabase();
    $vid = $row->getSourceProperty('vid');
    $query = $database
      ->select('workbench_moderation_node_history', 'wm')
      ->fields('wm', ['state'])
      ->condition('wm.vid', $vid)
      ->orderBy('wm.stamp', 'DESC')
      ->range(0, 1);
    $value = $query
      ->execute()
      ->fetchField();
    if ($value) {
      $row->setSourceProperty('moderation_state', $value);
    }

    return parent::prepareRow($row);
  }
}
💬 Support request
Status

Closed: outdated

Version

9.3

Component
Migration 

Last updated about 1 hour ago

Created by

🇦🇺Australia Begun

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇮🇳India sandip.prajapati

    Hello
    can you please provide full code?

    I am getting error node class not exist.
    Error: Class "Drupal\my_module\Plugin\migrate\source\Node\Node" not found in include() (line 24 of C:\xampp\htdocs\d10_custom\web\modules\custom\mymodule\src\Plugin\migrate\source\D7NodeExtended.php).
    [warning] Drush command terminated abnormally.

    <?php
    
    namespace Drupal\my_module\Plugin\migrate\source\Node;
    
    use Drupal\migrate\MigrateExecutableInterface;
    use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
    use Drupal\migrate\ProcessPluginBase;
    use Drupal\migrate\Row;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Drupal\migrate\Plugin\migrate\source\SqlBase;
    
    
    
    
    
    /**
     * Extended version of core Drupal 7 node source from database.
     *
     * @MigrateSource(
     *   id = "d7_node_extended",
     *   source_module = "node"
     * )
     */
    class D7NodeExtended extends Node {
     /**
       * {@inheritdoc}
       */
      public function prepareRow(Row $row) {
        // Make the node's moderation state available to migration.
        $database = $this->getDatabase();
        $vid = $row->getSourceProperty('vid');
        $query = $database
          ->select('workbench_moderation_node_history', 'wm')
          ->fields('wm', ['state'])
          ->condition('wm.vid', $vid)
          ->orderBy('wm.stamp', 'DESC')
          ->range(0, 1);
        $value = $query
          ->execute()
          ->fetchField();
        if ($value) {
          $row->setSourceProperty('moderation_state', $value);
        }
    
        return parent::prepareRow($row);
      }
    }
    
Production build 0.71.5 2024