If you are transitioning from Drupal 7 to modern versions like Drupal 9 or 10, one of the first things you will notice is that the familiar drupal_set_title() function has been removed. In the modern Symfony-based architecture, page titles are handled through the routing system and render arrays rather than a global function call.
In this guide, we will explore the various ways to dynamically set and alter page titles, whether you are working within a custom controller, a view, or a theme hook.
Using Title Callbacks in Routing
The most robust way to set a dynamic title for a custom route is through a title callback in your module's routing.yml file. This ensures that the title is correctly handled not just for the page display, but also for breadcrumbs and other site elements.
First, define your route and specify the _title_callback:
mymodule.test:
path: '/mymodule/test'
defaults:
_controller: '\Drupal\mymodule\Controller\Test::getContent'
_title_callback: '\Drupal\mymodule\Controller\Test::getTitle'
Next, implement the logic in your Controller class:
class Test {
/**
* Returns a dynamic page title.
*/
public function getTitle() {
return 'Foo: ' . \Drupal::config()->get('system.site')->get('name');
}
/**
* Returns a page render array.
*/
public function getContent() {
$build = array();
$build['#markup'] = 'Hello Drupal';
return $build;
}
}
Altering Titles via Preprocess Hooks
Sometimes you need to change the title of a page you didn't create, or you need to modify the title based on specific runtime conditions. In these cases, preprocess hooks are your best friend.
Changing the HTML Head Title
To change the title that appears in the browser tab (the <title> tag), use hook_preprocess_html():
function mymodule_preprocess_html(&$variables) {
$variables['head_title']['title'] = "Your Custom Title";
}
Changing the Visible Page Title Block
In modern Drupal, the page title is typically a block. You can intercept this block using hook_preprocess_block():
function mymodule_preprocess_block(&$variables) {
if ('page_title_block' == $variables['plugin_id']) {
$variables['content']['#title'] = "New Visible Title";
}
}
Alternatively, you can use the more specific hook_preprocess_page_title() to target the title directly:
function mymodule_preprocess_page_title(&$variables) {
if ($some_condition) {
$variables['title'] = 'New Dynamic Title';
}
}
Handling Titles for Entities and Views
Specialized content like Nodes, Users, and Views often requires specific hooks to alter their display labels.
Entity View Alter
If you want to change the title when viewing a specific entity (like a User profile or a Node), use the view_alter hook:
/**
* Implements hook_ENTITY_TYPE_view_alter().
*/
function mymodule_user_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
// Example: Use a custom field for the title instead of the username
$build['#title'] = $entity->get('field_display_name')->getString();
}
Dynamic Titles in Views
To change the title of a View programmatically, you can use hook_views_post_render(). This is particularly useful when the title needs to reflect the results of the view:
/**
* Implements hook_views_post_render().
*/
function mymodule_views_post_render(Drupal\views\ViewExecutable $view) {
if ($view->element['#view_id'] == 'id_of_view') {
$title = 'Custom View Title';
$view->setTitle($title); // Sets the H1
// Update the route title for the <head> tag
$route = \Drupal::routeMatch()->getCurrentRouteMatch()->getRouteObject();
$route->setDefault('_title_callback', function() use ($title) {
return $title;
});
}
}
Troubleshooting and Tips
If you find that your hooks are not firing or are being overridden by other modules, check your module's weight. Some modules or themes might be processing the title after yours. You can increase your module weight using Drush:
drush php:eval "module_set_weight('mymodule', 10);"
For those who prefer a low-code solution, the Automatic Entity Label module is a highly recommended community contribution. It allows you to define patterns for entity titles (using Tokens) without writing custom PHP.
Wrapping Up
While the loss of drupal_set_title() requires a bit more boilerplate code, the modern approach in Drupal provides much more control. By using routing callbacks, you ensure your titles are consistent across the site, while preprocess hooks give you the flexibility to modify titles on the fly. Always remember to distinguish between the HTML <head> title and the visible <h1> block title to ensure a great user experience.