Skip to main content

A bug bear that I have had for a while with Drupal content is how come the author of an article is actually their username.  I have an array of reasons to vent my dislike for this strategy... however, instead I will show you how to change it.  Albeit, programmatically!  Don't stress there actually isn't a huge amount of code to add.  In time I'll create a module so no coding is required.

 

Setting up account fields in the admin area

To begin let's add new fields for the people accounts.  Fields like first and last name.  Go to managing fields via

  1. Configuration > People > Account settings > Manage fields
  2. Click on Add field
  3. Under Add a new field, click on the drop down box - Select a field type - and go down to Text (plain)
  4. Enter a label... such as First name
  5. Click on Save and continue

Personally, I reduce the number of characters for a first name.  Either leave as is or enter a number that you feels covers the longest (real) name someone will use on your site.

Go through this process again if you also want to add a last name.

 

Editing the theme

As a rule, I create all of my own themes.  There are two files that need to be edited:

  1. {your-theme}.theme - found in themes/{your-theme}/ directory
  2. node.html.twig - generally found in themes/{your-theme}/templates/content directory

Directory architecture... below is a snapshot of the architecture that the theme of this site is running off. 

themes/

 ¬ {your-theme}/

 ¬ ¬ {your-theme}.info.yml

 ¬ ¬ {your-theme}.libraries.yml

 ¬ ¬ {your-theme}.theme

  ¬ ¬ templates/

  ¬ ¬ templates/content/

  ¬ ¬ templates/content/node.html.twig

  ¬ ¬ templates/content/page-title.html.twig

 

{your-theme}.theme

My purpose in adding the code was to meet the following requirements:

  • Match an existing content type named Article; and
  • Initially only add the last name field.  However, I have also shown the first name field in case you want to add it too.

Check if there is a hook_preprocess_node(array &$variables) function in the file.  In the theme for this site, the following code existed.  If the hook doesn't exist, you'll need to add the function in to your code.

/**
 * Node preprocess.
 */
function {your-theme}_preprocess_node(array &$variables) {
    $variables['node_author_pic'] = theme_get_setting('node_author_pic', '{your-theme}');
    $variables['node_tags'] = theme_get_setting('node_tags', '{your-theme}');
}

Adding code.  

To begin, we'll check to see if the node has a type of article.  

if ($variables['node']->getType() == 'article') {

}

To get the value of a node, the query is

$body = $variables['node']->get('body')->value;

$nid = $variables['node']->get('nid')->value;

However, while you can access then id value using the above call, the recommended method is to use:

$nid = $variables['node']->id();

So, you might try to get the node uid value doing the same.  $uid = $variables['node']->get('uid')->value;  Seems legit.  However, this will fail.  Instead use, $uid = $variables['node']->getOwnerId();  One you have the uid, getting the first and last values is done in a snap.  Get the authors details through an entity load using the user.uid value:  $author = \Drupal\user\Entity\User::load($uid).  Load the first name using the same call that was noted above for the body content.

$firstName = $author->get('field_firstname')->value;

 

/**
 * Node preprocess.
 */
function {your-theme}_preprocess_node(array &$variables) {
    $variables['node_author_pic'] = theme_get_setting('node_author_pic', '{your-theme}');
    $variables['node_tags'] = theme_get_setting('node_tags', '{your-theme}');

    if ($variables['node']->getType() == 'article') {
        $uid = $variables['node']->getOwnerId();
        $author = \Drupal\user\Entity\User::load($uid);
        $first_name = $author->get('field_firstname')->value;
        $last_name = $author->get('field_lastname')->value;
    }

}

You have the first and last name details for each node.  However, you will notice on your current site, the username is a link that is accessible too logged in users.

 

Generating the URL link

Scroll to the top of the file and check if the following exist beneath the <?php

<?php
use Drupal\Core\Url;
use Drupal\Core\Link;

No, then add them to your file.  There might already be another use case, such as use Drupal\file\Entity\File;  If so, add the two new use cases beneath forementioned use case.   Create the url:

$user_url = Url::fromRoute('user.page', ['user' => $author->id()]);

And the link, setting the title as the author's last name:

$link = Link::fromTextAndUrl($last_name, $user_url)->toString();

Finally, for this section set the variable actual_name to the author's name.  However, note if you want to only apply this if the user is logged in.

/**
 * Node preprocess.
 */
function {your-theme}_preprocess_node(array &$variables) {
    $variables['node_author_pic'] = theme_get_setting('node_author_pic', '{your-theme}');
    $variables['node_tags'] = theme_get_setting('node_tags', '{your-theme}');

    if ($variables['node']->getType() == 'article') {
        // status of the current user
        $logged_in = \Drupal::currentUser()->isAuthenticated();

        $uid = $variables['node']->getOwnerId();
        $author = \Drupal\user\Entity\User::load($uid);
        $first_name = $author->get('field_firstname')->value;
        $last_name = $author->get('field_lastname')->value;
        $user_url = Url::fromRoute('user.page', ['user' => $author->id()]);
        $link = Link::fromTextAndUrl($last_name, $user_url)->toString();
        $variables['actual_name'] = ($logged_in) ? $link : $last_name;
    }

}

 

Add / editing the node.html.twig

As noted earlier, the node.html.twig file is generally found in themes/{your-theme}/templates/content directory.  But your architecture structure might be different.  Again this file was already in the theme base.  It was written as follows:

<span class="node__submitted-info-text">By</span> {{ author_name }} on

However, with a change in css styling and bringing in Font Awesome icon the code became:

<span><i class="theme-color fas fa-user-circle"></i>  &nbsp; {{ actual_name }}</span>

You will notice that not only the change in css, also author_name changed to the variable set above to actual_name.

 

Comments!

Okay now that the username has been changed and works for a node... however, what about comments.  If your site is like ours, then comments are on a lot of them.  How do we alter the username in the comments section of the site?  Well actually most of the hard work has been completed.  So we don't duplicate code, lets take the core piece that was added to the _preprocess_node and put it into a new function that I'll call change_users_name.  

/* *
 * Change a username to an actual name
 */
function change_users_name($uid) {
    // status of the current user
    $logged_in = \Drupal::currentUser()->isAuthenticated();

    $author = \Drupal\user\Entity\User::load($uid);
    $first_name = $author->get('field_firstname')->value;
    $last_name = $author->get('field_lastname')->value;
    $user_url = Url::fromRoute('user.page', ['user' => $author->id()]);
    $link = Link::fromTextAndUrl($last_name, $user_url)->toString();
    return ($logged_in) ? $link : $last_name;
}

Now we need the preprocess_node to the new function.

/**
 * Node preprocess.
 */
function {theme}_preprocess_node(array &$variables) {
    $variables['node_author_pic'] = theme_get_setting('node_author_pic', 'bales');
    $variables['node_tags'] = theme_get_setting('node_tags', 'bales');

    if ($variables['node']->getType() == 'article') {

        $uid = $variables['node']->getOwnerId();
        $variables['actual_name'] = change_users_name($uid);
    }

}

Beneath the preprocess_node you might already have a preprocess_comment function.  On the theme I was developing the function existed as such

function bales_preprocess_comment(array &$variables) {
    $variables['comment_user_pic'] = theme_get_setting('comment_user_pic', 'bales');
}

As the grunt work has been completed all that is required is adding the following line

$variables['actual_name'] = change_users_name($variables['author_id']);

So the preprocess_comment now looks like

function bales_preprocess_comment(array &$variables) {
    $variables['comment_user_pic'] = theme_get_setting('comment_user_pic', 'bales');
    $variables['actual_name'] = change_users_name($variables['author_id']);
}

 

Add / editing the comment.html.twig

The final change is to the comment.html.twig file.   {{ author }} needs to be changed to {{ actual_name }}

<div class="single-comment-meta">
      <span>{{ author }} {{ created }}</span>
      {% if parent %}
        <p class="visually-hidden">{{ parent }}</p>
      {% endif %}
</div> 

Now becomes: 

<div class="single-comment-meta">
      <span>{{ actual_name }} {{ created }}</span>
      {% if parent %}
        <p class="visually-hidden">{{ parent }}</p>
      {% endif %}
</div>

Related articles

Andrew Fletcher07 May 2024
Understanding and resolving a Drupal render array error
Dealing with errors in Drupal development is a common occurrence, and understanding how to interpret and resolve them is essential for smooth development workflows. In this article, we'll delve into a specific error message related to render arrays in Drupal and discuss steps to diagnose and fix the...
Andrew Fletcher05 May 2024
Best practices for configuring Twig debug settings in Drupal 10
Alright, picture this: you're knee-deep in Drupal 10 development, churning out code like a pro. But hold up, what's this? Twig debug mode is still on in production? Cue the headaches. Suddenly, your beautifully crafted HTML is drowning in unnecessary output, and innocent contact form responses are...