Problem/Motivation
The search indexing process in Drupal fails to correctly handle HTML tags that contain whitespace characters (tabs, newlines) between the tag name and attributes. When node content contains such HTML tags (e.g., <a\n href="..."> or <a\t href="...">), the following issues occur:
1. PHP Warning: "Undefined array key" errors when the tag name with trailing whitespace is used as an array key
2. Incorrect search ranking: Tags are not properly recognized, resulting in improper scoring of search results
The root cause is that the code uses explode(' ', $value, 2) which only splits on space characters, not on other whitespace characters like tabs or newlines that are valid in HTML.
Error Example
Warning: Undefined array key "a " Drupal\search\SearchIndex->index()() (Line: 112)
Impact
This affects any content with multi-line HTML tags, which can occur when:
- Using custom text formats without CKEditor or other WYSIWYG editors
- Content is imported from external sources (RSS feeds, migrations, API integrations)
- Nodes are created programmatically via custom modules or APIs
- Database imports or bulk content updates
Note: Standard text formats (Full HTML, Basic HTML) typically use CKEditor, which automatically normalizes HTML. However, custom text formats without WYSIWYG editors allow users to enter multi-line HTML directly.
Steps to reproduce
Method 1: Using UI with custom text format (newline case)
- Create a custom text format without any filters:
- Go to
/admin/config/content/formats/add - Create a format without enabling any text editor
- Go to
- Create a node using this text format and enter HTML with newlines in the textarea:
<a href="https://example.com/" > Drupal Rocks </a>
- Save the node
- Run search indexing:
drush cron - Check the search index score in the database:
SELECT word, score FROM search_index WHERE word = 'rocks';
Expected score for <a> tag content: 11
Actual score with bug: 1 (incorrect - treated as plain text)
Method 1b: Using UI with custom text format (tab case)
Follow the same steps as Method 1, but enter HTML with a tab character between the tag name and attribute (represented as \t below):
<a\thref="https://example.com/">Drupal Rocks</a>
Method 2: Programmatic reproduction
use Drupal\node\Entity\Node;
$node = Node::create([
'type' => 'page',
'title' => 'Test multiline tags',
'body' => [
'value' => '<a
href="https://example.com/"
>
Drupal Rocks
</a>',
'format' => 'plain_text',
],
]);
$node->save();
Proposed resolution
Modify SearchIndex::index() to use preg_split() instead of explode() to properly handle all whitespace characters (space, tab, newline, etc.) between tag names and attributes.
Change in core/modules/search/src/SearchIndex.php:86:
// Before:
[$tagname] = explode(' ', $value, 2);
// After:
[$tagname] = preg_split('/\s+/', $value, 2);
This ensures that:
- Tag names are properly extracted regardless of whitespace type (space, tab, newline)
- Array key lookups succeed without warnings
- Search ranking scores are correctly applied according to HTML tag weights
Remaining tasks
Discuss how to handle existing search indexes created before this fix (reindex required vs. gradual update).
User interface changes
None. This is an internal bug fix with no UI changes.
Introduced terminology
None.
API changes
None. This is an internal implementation fix with no API changes.
Data model changes
None.
Release notes snippet
Fixed a bug in the search indexing process where HTML tags with whitespace characters (newlines, tabs) between tag names and attributes would cause PHP warnings and incorrect search ranking scores.
Issue fork drupal-3564713
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
u7aroComment #8
u7aroComment #9
u7aroI’ve created a merge request.
Comment #10
smustgrave commentedLeft a comment on the MR around the test.
Comment #11
u7aroComment #13
smustgrave commentedBelieve feedback for this one has been addressed. https://git.drupalcode.org/issue/drupal-3564713/-/jobs/8410601 shows the test coverage too.
Comment #18
godotislateCommitted and pushed to main, 11.x, 11.3.x. Thanks!
Comment #20
godotislate