Hook to change page title

Viewed 13538

I want to programmatically alter a page title in Drupal 8 so that it will be hard-coded in the theme file.

I'm attempting to use a hook function to preprocess_page_title, but it seems to not understand what page to change the title on.

Here's what I have so far:

function test_preprocess_page_title(&$variables) {
  if (arg(0) == 'node/12') {
    $variables['title'] = 'New Title';
  }
}

I figured the only way to make this change on one specific page is to set the node argument. Has any one figured out a way to override page title on Drupal?

5 Answers

Here's the method to preprocess your page :

function yourthemename_preprocess_page(&$variables) {
  $node = \Drupal::routeMatch()->getParameter('node');
  if ($node) {
    $variables['title'] = $node->getTitle();
  }
}

and in your template page.html.twig

{{title}}

There are a couple of solutions to change the page title

On template

/**
 * Implements hook_preprocess_HOOK().
 */
     function MYMODULE_preprocess_page_title(&$variables) {

      if ($YOUR_LOGIC == TRUE) {
          $variables['title'] = 'New Title';
     }
     }

On the node view page

/**
* Implements hook_ENTITY_TYPE_view_alter().
*/
function mymodule_user_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
      if ($YOUR_LOGIC == TRUE) {
  $build['#title'] = $entity->get('field_display_name')->getString();
  }
}

for a sample if you want to change user title

function mymodule_user_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
    if ($entity->getEntityTypeId() == 'user') {  
  $build['#title'] = $entity->get('field_first_name')->getString();
  }
}

On Controller or hook_form_alter

if ($YOUR_LOGIC == TRUE) {
$request = \Drupal::request();
if ($route = $request->attributes->get(\Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_OBJECT)) {
  $route->setDefault('_title', 'New Title');
 }
}

The Page Title is a block in Drupal 8. If you can find the plugin_id of the page title block (which is likely to be page_title_block), then you can override the title directly, with no need to change an existing twig template, using a block preprocessor. Your code may be similar to the following:

function vhs_preprocess_block(&$variables) {
  // This example restricts based on the actual URL; you can replace this with any other logic you wish.
  $request = \Drupal::request();
  $uri = $request->getRequestUri();
  if (
    isset($variables['elements']['#base_plugin_id']) &&
    $variables['elements']['#base_plugin_id'] == 'page_title_block' &&
    isset($variables['content']['#title']['#markup']) &&
    strpos($uri, '/url-to-match') === 0 // replace with logic that finds the correct page to override
  ) {
    $variables['content']['#title']['#markup'] = 'My Custom Title';
  }
}

The example above uses the Drupal request object to grab and compare the actual URL. The initial question asked to match based on the node path; you could get that with something like:

$current_path = \Drupal::service('path.current')->getPath();

Then, in place of the strpos condition above, you could use:

$current_path == 'node/12'

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