A PHP script to migrate Drupal 6 Nodewords to Drupal 8 Metatag “meta descriptions”

If you’re trying to convert Drupal 6 Nodewords “meta description” fields to Drupal 8 Metatag meta description fields, the following PHP script may help you.

To be clear, I’m not saying that this code is perfect and will immediately solve your needs, or anything like that. It’s more like this code will help point you in the right direction if you’re trying to migrate your “meta description” field in D6 to D8. Please note that the code is crappy; I wrote it in a hurry. It also doesn’t do any error-checking.

One important point about this code is that I ignore “meta keywords” and any other custom “meta” fields you may have created with the D6 Nodewords module. Search engines don’t seem to use meta-keywords any more, and I’m really short on time, so all I’m doing is copying the D6 Nodewords “meta description” field to the equivalent field for the D8 Metatag module. (Custom Nodewords meta-fields are kept in a completely different table that I don’t even touch.)

The code is very inefficient because I went straight from the process of debugging to “Okay, this works,” and I didn’t make any effort to clean it up or make it run faster.

Given those warnings, along with the usual warning that you should never do anything like this on a production server, here is some PHP code that you’re going to need to modify to work for your Drupal 6 to Drupal 8 migration:

#!/Applications/MAMP/bin/php/php5.6.10/bin/php

<?php

  $d6_servername = "localhost";
  $d6_username   = "d6_user";
  $d6_password   = "d6_pass";
  $d6_dbname     = "aa_d6";

  $d8_servername = "localhost";
  $d8_username   = "d8_user";
  $d8_password   = "d8_pass";
  $d8_dbname     = "aa_d8";

  require_once('Node.php');

  function run_d8_query($d8_connection, $query) {
      #echo "running query: $query\n";
      if (!$d8_connection->query($query)) {
          printf("error: %s\n", $d8_connection->error);
      }
  }


  # connect to the databases
  $d6_conn = new mysqli($d6_servername, $d6_username, $d6_password, $d6_dbname);
  if ($d6_conn->connect_error) {
      die("Connection failed: " . $d6_conn->connect_error);
  }

  $d8_conn = new mysqli($d8_servername, $d8_username, $d8_password, $d8_dbname);
  if ($d8_conn->connect_error) {
      die("Connection failed: " . $d8_conn->connect_error);
  }


  # --------------------------------------
  # (1) get a list of nodes from D6 `node`
  # --------------------------------------
  $sql = "SELECT nid, vid, type FROM node ORDER BY nid ASC";
  $result = $d6_conn->query($sql);

  # an array to store the results
  $nodes = array();

  # note - i 'assume success' here
  while($row = $result->fetch_assoc()) {

      # correct the 'photo' type
      $type = $row["type"];
      if ($type == "photo") $type = "photod8";

      # create an initial Node
      $n = new Node($row["nid"], $row["vid"], $type, "no description");
       
      array_push($nodes, $n);
      #$n->print_details();   # debugging
  }
 

  # -------------------------------------
  # (2) get the description for each node
  # -------------------------------------

  # set $limit higher than the number of nodes in your database
  # once you're done debugging and you want to make the complete migration.
  # while you're debugging set it to something much lower, like 10 or 20.
  $limit = 20000;

  $count = 0;
  foreach($nodes as $n) {
      $nid = $n->nid;

      $count++;
      if ($count > $limit) break;

      #echo "nid: " . $nid . "\n";
      $sql = "SELECT content FROM nodewords WHERE id=$nid AND name='description'";

      #echo "about to get result\n";
      $result = $d6_conn->query($sql);

      # note: i assume success here
      #echo "about to get row\n";
      if ($row = $result->fetch_assoc()) {
          $desc = $row["content"];
          #echo $desc . "\n";
          $n->description = $desc;
      }
  }

  // $count = 0;
  // foreach($nodes as $n) {
  //     $count++;
  //     if ($count > $limit) break;
  //     echo $n->description . "\n";
  // }


  # ------------------------------------------------
  # (3) massage the description to get what D8 needs
  # ------------------------------------------------

  # D8 looks like this when it has no keywords:
  # a:2:{s:11:"description";s:54:"This is a test description. Yada yada yada. More yada.";s:8:"referrer";s:11:"no-referrer";}
  # what i want from this initial loop is this:
  #    s:54:"This is a test description. Yada yada yada. More yada.";

  $count = 0;
  foreach($nodes as $n) {
      $count++;
      if ($count > $limit) break;
     
      # get a subset of the description
      $newDesc = substr($n->description, 17);
     
      # trim the end of that
      $descLen = strlen($newDesc);
      $newDesc = substr($newDesc, 0, $descLen-1);
     
      # find the first and last double-quotes in the string
      $firstQuotePos = strpos($newDesc, "\"");
      #echo "\n";
      #echo "firstQuotePos = " . $firstQuotePos . "\n";

      # trim off the first quote, and the last two characters
      $remainingDesc = substr($newDesc, $firstQuotePos+1, $descLen-2);
      $len = strlen($remainingDesc);
      $remainingDesc = substr($remainingDesc, 0, $len-2);
     
      # now, if there are no quotes in the remaining description, we're done,
      # but if there are quotes they need to be replaced
      $remainingDesc = str_replace("\"", "'", $remainingDesc);
      #$echo $remainingDesc . "\n";

      # rebuild the description to look like this:
      #    s:54:"This is a test description. Yada yada yada. More yada.";
      $len = strlen($remainingDesc);
      $res = "s:" . strval($len) . ":\"" . $remainingDesc . "\";";
      #echo "$res" . "\n";

      # assign it
      $n->description = $res;
  }


  # -------------------------------------------------
  # (4) make the description right for D8
  # i separated this step out in case i need to debug
  # stuff
  # -------------------------------------------------

  $prefix = "a:2:{s:11:\"description\";";
  $suffix = "s:8:\"referrer\";s:11:\"no-referrer\";}";
  $count = 0;
  foreach($nodes as $n) {
      $count++;
      if ($count > $limit) break;
      $n->description = $prefix . $n->description . $suffix;
  }


  # ----------------------------------
  # (5) insert new description into D8
  # ----------------------------------

  $count = 0;
  foreach($nodes as $n) {

      $count++;
      if ($count > $limit) break;
      echo "" . $count . "\n";

      $nid  = $n->nid;
      $vid  = $n->vid;
      $type = $n->type;
      $desc = $n->description;

      $safeDesc = mysql_real_escape_string($desc);
      $sql = "INSERT INTO node__field_meta_tags (bundle, deleted, entity_id, revision_id, langcode, delta, field_meta_tags_value) VALUES ('$type', 0, $nid, $vid, 'en', 0, '$safeDesc')";
      run_d8_query($d8_conn, $sql);

  }


  # ---------------------------------------------------
  # (6) insert new description into D8 (revision table)
  #     this is basically the same query as the
  #     previous one, but to the 'revisions' table
  # ---------------------------------------------------

  $count = 0;
  foreach($nodes as $n) {

      $count++;
      if ($count > $limit) break;
      echo "" . $count . "\n";

      $nid  = $n->nid;
      $vid  = $n->vid;
      $type = $n->type;
      $desc = $n->description;

      $safeDesc = mysql_real_escape_string($desc);
      $sql = "INSERT INTO node_revision__field_meta_tags (bundle, deleted, entity_id, revision_id, langcode, delta, field_meta_tags_value) VALUES ('$type', 0, $nid, $vid, 'en', 0, '$safeDesc')";
      run_d8_query($d8_conn, $sql);

  }


  // $count = 0;
  // foreach($nodes as $n) {
  //     $count++;
  //     if ($count > $limit) break;
  //     echo "\n";
  //     echo $n->nid . "\n";
  //     echo $n->description . "\n";
  // }


  $d6_conn->close();
  $d8_conn->close();
 
  echo "\n";
  echo "CLEAR THE CACHE!\n";
 
?>

For that to work, you’ll also need to have this code in a file named Node.php in the same directory:

<?php

  class Node
  {
      var $nid;
      var $vid;
      var $type;
      var $description;

      function Node($nid, $vid, $type, $description)
      {
          $this->nid = $nid;
          $this->vid = $vid;
          $this->type = $type;
          $this->description = $description;
      }
 
      # for debugging
      function print_details()
      {
          printf("nid: %s, vid: %s, type: %s\n", $this->nid, $this->vid, $this->type);
      }

  }

?>

Again, sorry, but I offer no support for this code. I only help that it helps point you in the right direction if you need to migrate your Drupal 6 meta description field data to Drupal 8. (Good luck.)