Problem/Motivation

It is easy to implement hook_help() incorrectly and cause visual defects in themes like Bartik.

For example, the Redirect module does:

/**
 * Implements hook_help().
 */
function redirect_help($route_name, RouteMatchInterface $route_match) {
  $output = '';
  switch ($route_name) {
    case 'redirect.fix_404':
      $output = '<p>' . t('This page lists all paths that have resulted in 404 errors and do not yet have any redirects assigned to them.') . '</p>';
      break;
  }
  return $output;
}

This results in a spurious empty block on the page which has a border.

Proposed resolution

Treat an empty string the same as a NULL.

Remaining tasks

User interface changes

None

API changes

Just an API tweek - treat an empty string the same as a NULL.

Data model changes

None

Comments

alexpott created an issue. See original summary.

alexpott’s picture

Category: Task » Bug report

Actually this is a regression from Drupal 7. Here is the code that gets the help for a path...

/**
 * Returns the help associated with the active menu item.
 */
function menu_get_active_help() {
  $output = '';
  $router_path = menu_tab_root_path();
  // We will always have a path unless we are on a 403 or 404.
  if (!$router_path) {
    return '';
  }

  $arg = drupal_help_arg(arg(NULL));

  foreach (module_implements('help') as $module) {
    $function = $module . '_help';
    // Lookup help for this path.
    if ($help = $function($router_path, $arg)) {
      $output .= $help . "\n";
    }
  }
  return $output;
}

So if hook returns an empty string it won't be added to the $output... if ($help = $function($router_path, $arg)) {.

I think it is worth fixing this behaviour in Drupal 8 as the current behaviour in HEAD if very unexpected.

alexpott’s picture

Status: Active » Needs review
Issue tags: +Needs tests
StatusFileSize
new764 bytes
alexpott’s picture

StatusFileSize
new4 KB
new4.75 KB

Here's a test that shows the problem.

The last submitted patch, 4: 2707109-4.test-only.patch, failed testing.

jhodgdon’s picture

Status: Needs review » Needs work

This entire test and patch looks great, except ...

+++ b/core/modules/help/tests/modules/help_page_test/help_page_test.module
@@ -17,6 +17,15 @@ function help_page_test_help($route_name, RouteMatchInterface $route_match) {
+function template_preprocess_block_help(&$variables) {
+  $a = 1;
 }

What is this function? Maybe it was some debugging code you left in by mistake?

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new535 bytes
new4.68 KB

@jhodgdon lol yep :)

dave reid’s picture

+++ b/core/modules/help/src/Plugin/Block/HelpBlock.php
@@ -97,10 +97,12 @@ protected function getActiveHelp(Request $request) {
+        if (!is_array($item)) {
+          $item = ['#markup' => $item];
+        }
+        $build[] = $item;

Minor but not needed to reassign $item? This also feels like it reads cleaner:

$build[] = is_array($item) ? $item : ['#markup' => $item];

alexpott’s picture

StatusFileSize
new857 bytes
new4.58 KB

Maybe this approach is slightly neater...

alexpott’s picture

Title: hook_help() should treat an empty string and NULL as the same value » Help block should be displayed when hook_help() implementations return an empty string
StatusFileSize
new1.87 KB
new5.7 KB

So actually given https://www.drupal.org/core/d8-bc-policy#plugins let's go a little bit further and clean up the block plugin to be a little easier to understand. I implemented #8 too.

There is a further issue to address. I think hook_help is making incorrect assumptions about how module invoke all works because I don't think the is_array() is working as expected. But this is the stuff of followups.

alexpott’s picture

Issue tags: -Needs tests +Contributed project blocker, +rc target triage

I'm tagging this as a contributed project blocker because the behaviour change between d7 and d8 is subtle and easy to miss and I'm not sure we want to file issues like #2707105: Redirect's hook_help returns an empty string on all calls against all contrib... the pattern of setting $output = ''; and returning it is really common. So common I think it is worth discussing this as a potential rc target because 6 months waiting for this fix feels like a long time.

jhodgdon’s picture

Title: Help block should be displayed when hook_help() implementations return an empty string » Help block should not be displayed when hook_help() implementations return an empty string

I completely agree this is a non-disruptive change -- it is changing the API behavior to be what everyone would expect it to be, not to mention what it was in D7.

Fixed the title, which had gotten reversed from what it should have been.

The patch looks great, except for a number of comment nitpicks:

  1. +++ b/core/modules/help/src/Tests/HelpBlockTest.php
    @@ -0,0 +1,56 @@
    + * Tests display of help block
    

    nitpick: needs to end in .

  2. +++ b/core/modules/help/src/Tests/HelpBlockTest.php
    @@ -0,0 +1,56 @@
    +    // Login the root user to ensure as many admin links appear as possible on
    

    nitpick: Log in is a verb; login is a noun/adjective.

  3. +++ b/core/modules/help/src/Tests/HelpBlockTest.php
    @@ -0,0 +1,56 @@
    +    // Login the root user to ensure as many admin links appear as possible on
    +    // the module overview pages.
    +    $this->drupalLogin($this->adminUser);
    

    This comment is also not accurate. We're not using the root user (which would be user 1), but an admin user created in the setUp() method.

  4. +++ b/core/modules/help/tests/modules/help_page_test/help_page_test.module
    @@ -17,6 +17,11 @@ function help_page_test_help($route_name, RouteMatchInterface $route_match) {
    +  // to display
    

    nitpick: this should end in .

alexpott’s picture

StatusFileSize
new2 KB
new5.29 KB

Fixed on the review points from #12 - funnily enough there's no need to log in at all so just removed all of that.

jhodgdon’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new3.52 KB

Yeah, the test module gives TRUE as access to those pages. Much cleaner.

So I think this is ready to go, assuming the test bot agrees on the latest patch. Would it make sense to upload a test-only patch just to make sure it still fails in its current lean-and-mean state? I think it would... so here is one (I just edited the patch file from #13 and took out the HelpBlock portion).

Assuming this one fails, and the one in #13 passes, we're good to go. Hopefully having this patch here will not cause the test bot to test it over and over and set the issue to Needs Work.

alexpott’s picture

StatusFileSize
new5.29 KB

Yeah it will cause the bot to have fun with the issue so re-uploading #13

The last submitted patch, 14: 2707109-13-test-only-FAIL.patch, failed testing.

xjm’s picture

Priority: Normal » Major
Issue tags: -Contributed project blocker

So this is not really a contributed project blocker because it can be worked around by returning NULL. I'd call it major though because of the unexpected visual regressions.

alexpott’s picture

The reason I added "contributed project blocker" is that the pattern of returning an empty string worked in D7 and it is super super easy to miss that your module is causes this visual issue and there is not much a site owner can do if they want to have the help module enabled.

  • catch committed 0cbd30d on 8.2.x
    Issue #2707109 by alexpott, jhodgdon: Help block should not be displayed...
catch’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: -rc target triage +rc target

Makes sense to do this in RC - it's user-facing and at least with the current patch can't be fixed in a patch release.

Committed/pushed to 8.2.x and cherry-picked to 8.1.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.