2

This is the first time I'm using the preprocees hook, apologies in advance.

I added a placeholder, {{user-uid}}, in a custom block body field, <a href="advisor/{{user-uid}}">Advisor Page</a></h5>.

My code is very simple, I have this hook theme.

    function boostrap_kampuster_preprocess_block(&$variables) {
        if (isset($variables['content']['#block_content'])) {
            $content = $variables['content']['#block_content'];
            
            /** custom block ID is 4 **/
            if( method_exists($content,'id') && $content->id() == '4') {
    
                $body = $variables['content']['body'][0]['#text'];
                
                $vars['user'] = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
                $body=str_replace('{{user-uid}}',$vars['user'],$body);
            }
        }
    }

I am not getting any errors but the function is not doing what it is supposed to do and replace {{user-uid}} with logged in user's ID either.

FYI, I cleared caches several times.

1
  • 1
    Before going the custom route, try the Token Filter module, it should work out of the box for common tokens like [current-user:id] and is more in line with the Drupal way of doing things
    – Hudri
    Feb 15, 2021 at 11:32

2 Answers 2

1

Recommend using @4k4's answer instead.

There are a few issues here:

  1. You're setting your $body variable, but not setting the change in your $variables array. You can fix this by using a reference, update with $body = &$variables['content']['body'][0]['#text'];
  2. You're replacing with the user object rather than the user id. You can't insert an object into the middle of a string. You can get the id of the current users with just \Drupal::currentUser()->id().
  3. I'd recommend not setting the current user to $vars['user'] in a preprocess function when you're using $variables as the accepted parameter. It's pretty common to use $vars as a shorthand in a preprocess $variables function and randomly setting $vars['user'] here is definitely going to cause confusion for anyone reading this in the future.
  4. I'd also recommend not using {{ VARIABLE }} as a custom placeholder since D8 templates use twig and that is twig syntax. For the same reasons you wouldn't use <?php echo $VARIABLE; ?> as your custom placeholder.

Your code updated:

function boostrap_kampuster_preprocess_block(&$variables) {
  if (isset($variables['content']['#block_content'])) {
    $content = $variables['content']['#block_content'];
        
    /** custom block ID is 4 **/
    if( method_exists($content,'id') && $content->id() == '4') {
      // These lines updated.
      $body = &$variables['content']['body'][0]['#text'];
      $body = str_replace('{{user-uid}}', \Drupal::currentUser()->id(), $body);
      // As 4k4 pointed out - you must set a cache context or this won't work as expected.
      $variables['#cache']['contexts'][] = 'user';
    }
  }
}
2
  • thank you so much! What if I changed, {{user-uid}} to user-id. Would str_replace capture and change it?
    – Efe
    Feb 14, 2021 at 16:11
  • Yes. Note that you'll need to at least add the cache context as 4k4 mentioned, e.g. $variables['#cache']['contexts'][] = 'user';. If it were me, though, I'd look to use the lazy builder approach in 4k4's answer.
    – sonfd
    Feb 14, 2021 at 20:00
4

In addition to @sonfd answer you also need to consider caching. The easiest way would be to add a cache context:

$variables['#cache']['contexts'][] = 'user';

But then the database needs to store a cached version for each user.

Better for performance would be to postpone replacing the placeholder by attaching a lazy builder to the render array:

function mytheme_preprocess_block(&$variables) {
  $variables['#attached']['placeholders']['{{user-uid}}'] = [
    '#lazy_builder' => ['_mytheme_replace_uid', []],
  ];
}

which then returns the markup of the user UID:

function _mytheme_replace_uid() {
  return [
    '#markup' => \Drupal::currentUser()->id(),
    '#cache' => ['contexts' => ['user']],
  ];
}

Drupal 9

Drupal 9 requires using only trusted callbacks. So define a class implementing TrustedCallbackInterface or RenderCallbackInterface:

mytheme/src/MythemeLazyBuilders.php:

<?php

namespace Drupal\mytheme;

use Drupal\Core\Render\Element\RenderCallbackInterface;

class MythemeLazyBuilders implements RenderCallbackInterface {

  public static function replaceUid() {
    return [
      '#markup' => \Drupal::currentUser()->id(),
      '#cache' => ['contexts' => ['user']],
    ];
  }

}

and add it to the render array:

function mytheme_preprocess_block(&$variables) {
  $variables['#attached']['placeholders']['{{user-uid}}'] = [
    '#lazy_builder' => ['\Drupal\mytheme\MythemeLazyBuilders::replaceUid', []],
  ];
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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