In Drupal 7, I could change the page title with drupal_set_title(t('New page title'))
. When I try it in Drupal 8, I get a There is no such function error.
How can I change the page title?
As reported in drupal_set_title() and drupal_get_title() were removed that function is deprecated in Drupal 8.
For a dynamic title set from a controller, the code the change record suggests is the following one.
mymodule.test:
path: '/mymodule/test'
defaults:
_controller: '\Drupal\mymodule\Controller\Test::getContent'
_title_callback: '\Drupal\mymodule\Controller\Test::getTitle'
The controller code is the following one.
class Test {
/**
* Returns a 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;
}
}
Alternatively, as the same change record suggests, you could use the #title
property in a render array. This should be generally avoided, since the title for the page when fully rendered could be different from the title in other contexts (like in the breadcrumbs).
class Test {
/**
* Renders a page with a title.
*
* @return array
* A render array as expected by drupal_render()
*/
public function getContentWithTitle() {
$build = array();
$build['#markup'] = 'Hello Drupal';
$build['#title'] = 'Foo: ' . Drupal::config()->get('system.site')->get('name');
return $build;
}
}
Change the title tag in the head of your HTML document.
function mymodule_preprocess_html(&$variables) {
$variables['head_title']['title'] = $something;
}
Change the title that appears in the page content.
function mymodule_preprocess_block(&$variables) {
if ('page_title_block' == $variables['plugin_id']) {
$variables['content']['#title'] = $something;
}
}
$variables['head_title']['name']
on a Views page in the preprocess_html.
drupal_set_title() in Drupal 8
$request = \Drupal::request();
if ($route = $request->attributes->get(\Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_OBJECT)) {
$route->setDefault('_title', 'New Title');
}
drupal_get_title() in Drupal 8
$request = \Drupal::request();
if ($route = $request->attributes->get(\Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_OBJECT)) {
$title = \Drupal::service('title_resolver')->getTitle($request, $route);
}
Views
To change the view title, both <h1>
and <head><title>
, according to this.
Create a custom module and place the following in the .module file:
/**
* Implements hook_views_post_render().
*/
function mymodule_views_post_render(Drupal\views\ViewExecutable $view) {
if ($view->element['#view_id'] == 'id_of_view') {
if ($view->element['#display_id'] == 'id_of_display') {
$title = 'test';
$view->setTitle($title); // Sets h1
$route = \Drupal::routeMatch()->getCurrentRouteMatch()->getRouteObject();
$route->setDefault('_title_callback', function() use ($title) {
return $title; // sets <head><title>
});
}
}
}
$route = \Drupal::routeMatch()->getRouteObject(); $route->setDefault('_title', 'New Title');
Commented
Nov 19, 2021 at 14:59
That function was removed from Drupal 8.
Change record:
drupal_set_title() and drupal_get_title() were removed.
You could now set the title when defining the routes in modulename.routing.yml
.
Example of how it could be done, is shown the change record link above.
I found in D8 that if you're wanting to alter the title for an entity view, you can use hook_ENTITY_TYPE_view_alter(). For example, here's how you could change the view of a user entity with a field on the user "field_display_name", rather than the user ID as the title:
/**
* Implements hook_ENTITY_TYPE_view_alter().
*/
function mymodule_user_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
$build['#title'] = $entity->get('field_display_name')->getString();
}
I've found another way, which may be simpler if you don't have a controller and want to modify the title throughout your website. You can use it to modify the title based on the current node.
First, remove the tag in your html.html.twig Then, hook hook_page_attachments_alter
function mytemplate_page_attachments_alter(array &$page) {
$page['#attached']['html_head'][] = [
[
'#tag' => 'title',
'#value' => "My title"
],
'title'
];
}
You can get the current node of taxonomy term with
$node = \Drupal::routeMatch()->getParameter('node');
$term = \Drupal::routeMatch()->getParameter('taxonomy_term')
Getting the page title works fine as written in @rpayanm's answer. But setting it turned out to be quite complicated. Finally found out that hook_preprocess_HOOK()
could simply be used to preprocess the page title quite easily.
/**
* Implements hook_preprocess_HOOK().
*/
function MYMODULE_preprocess_page_title(&$variables) {
if ($MYLOGIC === TRUE) {
$variables['title'] = 'New Title';
}
}
And as already mentioned in other answers here you might additionally use hook_preprocess_html()
to set the HTML head title tag accordingly.
Take a look at Automatic Entity Label, a very well crafted contributed module for setting node titles and the like.
(Note that 'page title' is a more colloquial way of saying 'entity label', where 'page' is a content entity and 'label' encompasses the title and the equivalent for other entities e.g. comment subjects, taxonomy term names.)
While op appears to be asking for guidance on writing custom code, it's not clear from available details that custom code is the best recommendation. For readers without a very specific reason for duplicating a feature available from contributed code, the Drupal community strongly advises (and site owners strongly benefit from) adopting an existing module.
drupal_set_title()
and drupal_get_title()
both are removed from drupal 8 but the best part is this there is a separate block for page_title
. User can hide or add this block on any page/region.
There are 2 solutions for this.
title_block
on particular page and add new custom block with some markup for title. Now place this block just after the title_block
in drupal block section.By using hook_preprocess_block()
function in your custom_theme.theme
file.
Here is the code example:
function custom_themename_preprocess_block(&$variables) {
if ('page_title_block' == $variables['plugin_id']) {
$request = \Drupal::request();
$path = $request->getRequestUri(); // get current path
if(strpos($path, 'user')) { //check current path is user profile page
$variables['content']['#title'] = 'My Profile';
}
}
}
In my case I have used above 2nd method, which will work only for user profile page.
I struggled with this and tried all of the solutions above. The solution that finally worked was:
function mymodule_preprocess_html(&$variables) {
$variables['head_title']['title'] = $something;
}
but only after I updated my custom module weight:
drush php:eval "module_set_weight('mymodule', 10);"
i have changed the page_title block for user/uid to a different custom account field name like this :
function hook_preprocess_block(&$variables) {
$path = \Drupal::request()->getpathInfo();
$arg = explode('/', $path);
if (isset($arg[2]) && $arg[2] == 'user' && isset($arg[3])) {
if (isset($variables['elements']['content']['#type']) && $variables['elements']['content']['#type'] == 'page_title') {
$account = \Drupal\user\Entity\User::load($arg[3]);
if(isset($account) && isset($account->field_mycustomfield->value)){
$variables['content']['#title']['#markup']=$account->field_mycustomfield->value;
}
}
}
}
The code above suggested by @rpayanm to change the page title for Views doesn't seem to work anymore, so here is our solution that allows to add markup to the View title:
function my_module_views_post_render(ViewExecutable $view, array &$output, CachePluginBase $cache) {
$output['#post_render'][] = function ($content, array &$element) {
$element['#title']['#markup'] = 'test - <em>My new Title</em>';
return $content;
};
}
Tested on Drupal 10.2.7.
Had to do this in a controller which had a dynamic route and made an API call to build the content on the page. I did not want to make any additional API calls to slow the page down so using the _title_callback did not work for me. $details is the response from the API call.
$request = \Drupal::request();
if ($route = $request->attributes->get(\Drupal\Core\Routing\RouteObjectInterface::ROUTE_OBJECT)) {
$route->setDefault('_title', $details->name);
}
Thanks to others on this thread and this comment on drupal.org: https://www.drupal.org/node/2067859#comment-15250575