28

I know I could change the page title with drupal_set_title(t('Amy page title')), but when I try it in Drupal 8 I get the There is no such function error.

How can I change page title in Drupal 8?

10 Answers 10

29

As you can see here that function is deprecated in Drupal 8.

Titles on routes now can be set on various ways, depending on your use case. Previously just drupal_set_title() was called in whatever place. The following use cases exist:

Static title

For static titles you set a '_title' on the routing definition:

block.admin_add:
  path: '/admin/structure/block/add/{plugin_id}/{theme}'
  defaults:
    _controller: '\Drupal\block\Controller\BlockAddController::blockAddConfigureForm'
    _title: 'Configure block'
  requirements:
    _permission: 'administer blocks'

Dynamic title

If you write a controller and you need a dynamic title, for example depending on the site configuration, use _title_callback in the route defaults.

mymodule.test:
  path: '/mymodule/test'
  defaults:
    _controller: '\Drupal\mymodule\Controller\Test::getContent'
    _title_callback: '\Drupal\mymodule\Controller\Test::getTitle'

<?php
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;
  }
}
?>

Final title override

If you write a controller and you need to override the title from the route, you can return #title in the render array. This should generally to be avoided, since the title for the page when fully rendered could be different from the title in other contexts (like in the breadcrumb).

<?php
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;
  }

}
?>

Output flag of drupal_set_title()

The output validation in Drupal 8 is opposite to Drupal 7. We have to explicitly specify PASS_THROUGH and CHECK_PLAIN is by default in Drupal 7, whereas in Drupal 8 the situation is different. Output is auto escaped unless it is marked safe. Both t() and new FormattableMarkup return objects that will not be auto escaped.

$form['#title'] = $this->t('Add new shortcut');
$form['#title'] = $this->t("'%name' block", array('%name' => $info[$block->delta]['info']));
4

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;
  }
}
3

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.

3

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);
}
  • GET title works fine maybe everywhere. I wonder where to SET the title, cause in preprocess page it doesn't seem to work. – leymannx Mar 30 '17 at 9:35
1

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')
1

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.

1

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();
}
0

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 title tag accordingly.

0

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.

  1. Disable 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.
  2. 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.

  • after using this hook i set the value using $variables['content']['#title'] = 'Good Morning'; but when i check title its not changing , Let me know why – Manmeet Khurana Aug 17 '18 at 7:14
0

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);"

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.