In 5.x the following code would redefine the comment "delete" link to point somewhere else:

function module_link($type, $object = NULL) {
  if ($type == 'comment') {
    $links['comment_delete'] = array(
      'title' => t('delete'),
      'href' => 'other/delete/something',
    );
    return $links;
  }
}

In 6.x, it causes a WSOD after hanging for a few seconds. :(

This is because instead of a strings being passed into url() and check_plain(), they're instead arrays, as the link now looks like this:

  array
                  'comment_delete' => 
                    array
                      'title' => 
                        array
                          0 => string 'delete' (length=6)
                          1 => string 'delete' (length=6)
                      'href' => 
                        array
                          0 => string 'comment/delete/1' (length=16)
                          1 => string 'module/comment/1' (length=16)

Trying to track this down to see where the change was introduced.

Comments

webchick’s picture

Oh, incidentally, the node equivalent for this works fine. Also, echo 'something'; at the top of index.php will remove the WSOD in favour of barfing out errors everywhere:

# notice: Array to string conversion in /Users/webchick/Sites/6x/includes/common.inc on line 1270.
# notice: Array to string conversion in /Users/webchick/Sites/6x/includes/bootstrap.inc on line 715.
# warning: preg_match() expects parameter 2 to be string, array given in /Users/webchick/Sites/6x/includes/bootstrap.inc on line 718.

These are all related to url() and check_plain() being passed arrays rather than strings.

dvessel’s picture

I don't know how to fix this but it looks like how the links are altered. We use drupal_alter now, it used to be HOOK_link_alter.

http://api.drupal.org/api/function/comment_render

vladimir.dolgopolov’s picture

This related with nodes too:

(1) Create 2 modules with only hook_link():

Module 1:

function mymodule1_link($type, $object = NULL, $teaser = FALSE) {
  if ($type == 'node' and !$teaser) {
    $links['special_shared_link'] = array(
      'title' => t("title1"),
      'href' => "path/to/module1",
    );
    return $links;
  }
}

Module 2:

function mymodule2_link($type, $object = NULL, $teaser = FALSE) {
  if ($type == 'node' and !$teaser) {
    $links['special_shared_link'] = array(
      'title' => t("title2"),
      'href' => "path/to/module2",
    );
    return $links;
  }
}

(2) Create any node (a 'Page' e.g.)

(3) View the node (node/{nid})

You can see the notices and warning.

It's because of:

function module_invoke_all() {
...
  $return = array_merge_recursive($return, $result);
...
}
vladimir.dolgopolov’s picture

This is a test for the issue:


class TestCase223159 extends DrupalTestCase {
  function get_info() {
    return array(
      'name' => t('[223159] Regression: hook_link() merges rather than overwrites'),
      'desc' => t('In 6.x, it causes a WSOD after hanging for a few seconds. :( This is because instead of a strings being passed into url() and check_plain(), they\'re instead arrays, as the link now looks like this.'),
      'group' => t('Drupal 7 Tests'),
    );
  }
  
  function testIssue() {
    // We will create 2 modules.
    // They add the the same link's name (by hook_link()) in a node ('page').
    // After enabling module1 there should be link1. This pass.
    // After enabling module2 there should be only link2. This fail as now.
    $node = $this->createPage();

    // requested link key
    $link_name = $this->randomName();
    $module_text = <<< EOF
<?php
function {module_name}_link(\$type, \$object = NULL, \$teaser = FALSE) {
  if (\$type == 'node' and !\$teaser) {
    \$links['$link_name'] = array(
      'title' => t("{module_name} link"),
      'href' => "link/to/{module_name}",
    );
    return \$links;
  }
}
EOF;

  	// create module 1
  	$module_name1 = $this->randomName();
  	$module_text1 = str_replace('{module_name}', $module_name1, $module_text);
  	$this->createModule($module_name1, $module_text1);

    // here must be the link from module 1
    $this->drupalGet("node/{$node->nid}");
    $this->assertWantedRaw("$module_name1 link", 'Check link 1');

  	// create module 2 with the same requested link
  	$module_name2 = $this->randomName();
  	$module_text2 = str_replace('{module_name}', $module_name2, $module_text);
  	$this->createModule($module_name2, $module_text2);

    // here must be the link from module 2 now
    $this->drupalGet("node/{$node->nid}");
    $this->assertWantedRaw("$module_name2 link", 'Check link 2');

    $this->deleteModule($module_name1);
    $this->deleteModule($module_name2);
  }

  function createPage() {
    $this->drupalVariableSet('node_options_page', array('status', 'promote'));
    $web_user = $this->drupalCreateUserRolePerm(array('edit own page content', 'create page content'));
    $this->drupalLoginUser($web_user);
    $edit = array();
    $edit['title']    = '!SimpleTest test node! ' . $this->randomName(10);
    $edit['body']     = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
    $this->drupalPost('node/add/page', $edit, 'Save');
    $this->assertWantedRaw(t('!post %title has been created.', array ('!post' => 'Page', '%title' => $edit['title'])), 'Page created');
    $node = node_load(array('title' => $edit['title']));
    $this->assertNotNull($node, 'Node found in database. %s');
    return $node;
  }


  function createModule($module_name, $module_text, $module_core = '7.x') {
    $module_dir = "sites/all/modules/$module_name";
    $module_file = "$module_dir/$module_name.module";
    $module_file_info = "$module_dir/$module_name.info";
    if (file_check_directory($module_dir, FILE_CREATE_DIRECTORY)) {
      $info = <<< EOF
name = "$module_name module"
description = "$module_name module for test. Delete it when you see it."
package = Temporary
core = $module_core

EOF;
      if ($fp = @fopen($module_file_info, 'w')) {
        fwrite($fp, $info);
        fclose($fp);
      }
      if ($fp = @fopen($module_file, 'w')) {
        fwrite($fp, $module_text);
        fclose($fp);
      }
      $this->drupalModuleEnable($module_name);
    }
  }

  function deleteModule($module_name) {
    $module_dir = "sites/all/modules/$module_name";
    $module_file = "$module_dir/$module_name.module";
    $module_file_info = "$module_dir/$module_name.info";
    @unlink($module_file);
    @unlink($module_file_info);
    @rmdir($module_dir);
  }

}
catch’s picture

Version: 7.x-dev » 6.x-dev

Moving back to D6, hook_link() is dead in Drupal 7.

dpearcefl’s picture

Status: Active » Postponed (maintainer needs more info)

Is this an issue in current D6?

dpearcefl’s picture

Status: Postponed (maintainer needs more info) » Active

Status: Active » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.