Migrating vBulletin Threads with vbulletin_forum.inc

Last updated on
30 April 2025

With roles, users and forum structure in place, we can now look at migrating threads from the vBulletin database threads table with something like the following in the vbulletin_forum.inc file

class vBulletinThreadMigration extends Migration {
  public function __construct() {
    parent::__construct();
    $this->description = t('Migrate vBulletin forum threads');

    // Set the source table's primary key
    $this->map = new MigrateSQLMap(
      $this->machineName,
      array(
        'threadid' => array(
          'type' => 'int',
          'unsigned' => TRUE,
          'not null' => TRUE,
          'description' => 'vBulletin forum threads',
          'alias' => 't',
        ),
      ),
      MigrateDestinationNode::getKeySchema(),
      'for_forum_migration'
    );

    // Set the query to get the source object
    $query = Database::getConnection('default', 'for_forum_migration')
      ->select('thread', 't')
      ->fields('t', array(
        'threadid',
        'title',
        'firstpostid',
        'lastpost',
        'forumid',
        'pollid',
        'open',
        'replycount',
        'hiddencount',
        'postusername',
        'postuserid',
        'lastposter',
        'dateline',
        'views',
        'iconid',
        'notes',
        'visible',
        'sticky',
        'votenum',
        'votetotal',
        'attach',
        'similar',
        'deletedcount',
        'lastpostid',
        'description',
        'prefixid',
        'taglist',
        'vbseo_linkbacks_no',
        ));

    // vBulletin thread doesn't include the first post text, so get it by joining with the post table, matching firstpostid and postid

    $query->join('post', 'p', "t.firstpostid = p.postid");
    $query->addField('p', 'pagetext');

    $this->source = new MigrateSourceSQL($query, array(), NULL, array('map_joinable' => FALSE));

    // Define the destination as the D7 forum node

    $this->destination = new MigrateDestinationNode('forum', array('text_format' => 'bbcode'));

    // Map fields from vBulletin threads to D7 forum nodes

    $this->addFieldMapping('uid', 'postuserid')
         ->sourceMigration('vBulletinUser');

    $this->addFieldMapping('created', 'dateline');

    $this->addFieldMapping('changed', 'lastpost');

    $this->addFieldMapping('status', 'visible');

    $this->addFieldMapping('promote')
         ->defaultValue(0);

    $this->addFieldMapping('sticky', 'sticky');

    $this->addFieldMapping('title', 'title');

    $this->addFieldMapping('field_tags', 'taglist')
         ->separator(',');

    $this->addFieldMapping('comment', 'open');

    // vBulletin thread forumid needs to map to tid in the D7 forum table 

    $this->addFieldMapping('taxonomy_forums', 'forumid')
         ->sourceMigration('vBulletinForum');

    $this->addFieldMapping('body', 'pagetext');

    $this->addFieldMapping('pathauto')
         ->defaultValue(0);

    $this->addFieldMapping('field_forum_icon', 'iconid');

    // Flag up any issues to address

    $this->addFieldMapping(NULL, 'deletedcount')
         ->description('Find out what deletedcount is for')
         ->issueGroup(t('Owner Issues'))
         ->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_MEDIUM)
         ->issueNumber(0012);

    $this->addFieldMapping(NULL, 'votenum')
         ->description('Decide to drop or implement thread votes')
         ->issueGroup(t('Owner Issues'))
         ->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_MEDIUM)
         ->issueNumber(0012);

    $this->addFieldMapping(NULL, 'votetotal')
         ->description('How does D7 calculate total and average votes')
         ->issueGroup(t('Owner Issues'))
         ->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_MEDIUM)
         ->issueNumber(0012);

    // Unmapped source fields

    $this->addFieldMapping(NULL, 'pollid') ->description(t('Used only once in vBulletin and not needed in D7'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'postusername') ->description(t('Username generated by postuserid and sourceMigration from vBulletinUser'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'lastposter') ->description(t('Used in vBulletin, but no need to migrate as D7 identifies last poster from post date'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'views') ->description(t('Used in vBulletin, but not obvious and probably not needed in D7'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'notes') ->description(t('Never used in vBulletin and not needed in D7'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'attach') ->description(t('Not used in vBulletin and not needed in D7'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'similar') ->description(t('Use D7 or a contrib to find similar content if this featured is needed'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'lastpostid') ->description(t('D7 creates this automatically from post created dates'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'description') ->description(t('Barely used in vBulletin and not needed in D7'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'prefixid') ->description(t('Not used in vBulletin and not needed in D7'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping(NULL, 'vbseo_linkbacks_no') ->description(t('Always 0 in vBulletin and not needed in D7'))
           ->issueGroup(t('DNM'));

    // Unmapped destination fields

    $this->addFieldMapping('revision') ->description(t('vBulletin does not use node revisions so nothing to import'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping('log') ->description(t('vBulletin did not use a thread log so nothing to import'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping('language') ->description(t('English language only set at site level'))
           ->issueGroup(t('DNM'));
    $this->addFieldMapping('tnid') ->description(t('No translation so tnid not required'))
           ->issueGroup(t('DNM'));

    }

    public function prepare($node, stdClass $row) {
      if ($row->open == '1') {
        $node->comment = '2';
    }
  }
}

When you start a thread in vBulletin, the text content of the thread is stored in the vBulletin database 'post' table in a 'pagetext' field, and linked back the thread with a 'firstpostid' reference. However, in D7 the first post is stored as 'body' text in the thread node. As a result, we need to join the vBulletin 'thread' source table with the 'post' table, matching the 'firstpostid' and 'postid' fields respectively, using...

    $query->join('post', 'p', "t.firstpostid = p.postid");
    $query->addField('p', 'pagetext');

The addFieldMApping then sources the pagetext field data so we can map it to the relevant D7 forum thread node's body field using...

    $this->addFieldMapping('body', 'pagetext');

Help improve this page

Page status: Not set

You can: