Comment puis-je afficher par programme un bloc?

34

Je développe un site utilisant Drupal 8 beta-14. J'ai créé un bloc d'affichage de différents termes et maintenant je veux l'afficher en utilisant du code. Comment puis-je l'afficher par programme? Je le faisais dans Drupal 7 en utilisant ce code mais je suis confus à propos de Drupal 8.

$block = module_invoke('block', 'block_view', '4');
$text_block = render($block['content']);
rashidkhan
la source

Réponses:

70

Il existe deux types de blocs et la méthode de rendu des deux est un peu différente:

Blocs de contenu

Les blocs de contenu sont des blocs que vous créez dans l'interface. Ils ressemblent beaucoup à des structures de données configurables par nœuds, avec des champs, etc.

$bid = ??? // Get the block id through config, SQL or some other means
$block = \Drupal\block_content\Entity\BlockContent::load($bid);
$render = \Drupal::entityTypeManager()->
  getViewBuilder('block_content')->view($block);
return $render;

Blocs de plugin

Les blocs peuvent également être des plugins, définis dans différents modules. Un exemple pourrait être le bloc de fil d'Ariane. Si vous voulez les rendre, vous devrez utiliser le gestionnaire de plugins de blocs.

$block_manager = \Drupal::service('plugin.manager.block');
// You can hard code configuration or you load from settings.
$config = [];
$plugin_block = $block_manager->createInstance('system_breadcrumb_block', $config);
// Some blocks might implement access check.
$access_result = $plugin_block->access(\Drupal::currentUser());
// Return empty render array if user doesn't have access.
// $access_result can be boolean or an AccessResult class
if (is_object($access_result) && $access_result->isForbidden() || is_bool($access_result) && !$access_result) {
  // You might need to add some cache tags/contexts.
  return [];
}
$render = $plugin_block->build();
// In some cases, you need to add the cache tags/context depending on
// the block implemention. As it's possible to add the cache tags and
// contexts in the render method and in ::getCacheTags and 
// ::getCacheContexts methods.
return $render;

Entités de configuration

Les blocs sont partagés pour les deux types, c'est qu'une fois que vous les insérez dans une région, vous allez créer une entité de configuration qui possède tous les paramètres du bloc. Dans certains cas, il sera plus utile de gérer les entités de configuration. Étant donné que le même bloc peut être placé dans plusieurs régions avec et avec une configuration différente, il peut être plus difficile d'utiliser les entités de configuration de bloc. La bonne chose est que vous pourriez vouloir rendre un bloc avec une configuration spécifique, la mauvaise chose est que les identifiants de configuration peuvent changer en jouant avec l'interface, de sorte que le code pourrait ne pas fonctionner après avoir laissé les utilisateurs utiliser l'interface de bloc.

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;
googletorp
la source
2
La question ne précise pas s'il s'agit de rendre une entité de configuration de bloc (un placement de bloc préconfiguré) ou un plugin de bloc avec une configuration codée en dur. Ce qui est logique car cette différence n'existe pas dans 7.x. Ceci est plus flexible car l'autre nécessite en fait un bloc spécifique qui doit être placé dans un thème et une région donnés. Cependant, vous ne devez jamais les créer à la main. Utilisez la méthode createInstance () du gestionnaire de plugins pour cela avec l'ID du plugin, où vous pouvez également fournir un tableau de configuration $ ...
Berdir
2
En outre, vous voudrez peut-être envisager d'appeler la méthode access () en premier dans le cas où l'accès au bloc est limité, par exemple, à une certaine autorisation par ce bloc. Pouvez-vous améliorer un peu votre réponse à ce sujet? Peut alors devenir une ressource utile :)
Berdir
1
@Berdir Cela fait un moment, mais j'ai finalement réussi à améliorer la réponse. Avec toutes les différentes mises en cache en cours, l'utilisation directe du plugin n'est probablement utile que dans des situations limitées.
googletorp
4
L'inconvénient de l'utilisation du gestionnaire de plugins de blocs createInstance () est que le tableau de rendu résultant n'est pas exécuté par le biais de la thématisation des blocs, vous ne pouvez donc pas utiliser le bloc - blockname.twig.html, par exemple. L'alternative est de créer un bloc pour votre thème, mais laissez-le désactivé, puis dans votre code faites: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('block') -> view ($ block); ``
joachim
1
Non - Un autre trou de lapin. Le code pour les écrans blancs du bloc de contenu (avec le tristement célèbre "Le site Web a rencontré une erreur inattendue. Veuillez réessayer plus tard.") Le second se rapproche - Mais affiche un message cryptique sur le bloc manquant ou quelque chose ... n'est pas vrai parce que j'essaie un bloc système - le truc alimenté par drupal).
sea26.2
16

Pour afficher uniquement votre bloc dans vos modèles avec prétraitement, la meilleure façon est

$block = \Drupal\block\Entity\Block::load('my_block_id');
$variables['My_region'] = \Drupal::entityManager()
          ->getViewBuilder('block')
          ->view($block);

Et dans votre page.html.twigou node.html.twigou xxx.html.twigutilisez votre variable My_region comme ceci:

{% if page.My_region %}
    {{ page.My_region }}
{% endif %}

Et dans un tableau rendable (module personnalisé) par exemple dans un contrôleur personnalisé dans content ():

public function content() {
    $block = \Drupal\block\Entity\Block::load('my_block_id');
    $block_content = \Drupal::entityManager()
      ->getViewBuilder('block')
      ->view($block);

          return array(
        '#type' => 'container',
        '#attributes' => array(
          'class' => array("Myclass"),
        ),
        "element-content" => $block_content,
        '#weight' => 0,
      );
}

En utilisant drupal_rendern'est pas utile car Drupal assume déjà le rendu en D8 et c'est obsolète . Vous devez utiliser à la \Drupal::service('renderer')->renderRoot()place.

C'est un peu lourd, il vaut mieux utiliser le système de surface maximale et n'ajoute pas de bloc de charge du pré-processus. Dans le cas de l'utilisation d'un contrôleur dans vos modules, cela semble une utilisation justifiée.

woprrr
la source
Cette implémentation de contrôleur est exactement ce que je cherchais. Merci!
Mrweiner
Je suis intéressé par cette implémentation de contrôleur pour un cas d'utilisation similaire auquel je fais face. Mais je ne trouve aucune documentation sur la element-contentpropriété dans un tableau de rendu. Savez-vous où c'est documenté?
Eria
Je ne sais pas pourquoi, mais \Drupal\block\Entity\Block::loadne retourne pas tout le temps un bloc. Il ne renvoie quelque chose que si le bloc que je charge est placé dans la vue dans la disposition des blocs . S'il n'est pas placé, il renvoie null.
Arthur Attout
Cette réponse doit être mise à jour pour être utilisée\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman
6

En plus de la première réponse ... Si vous voulez rendre un bloc à partir d'une vue, vous devrez peut-être faire les choses un peu différemment.

$view = views_embed_view('my_view_name', 'my_display_name');

(nom d'affichage par exemple -> block_1)

Puisque nous allons le passer à twig, nous n'avons pas besoin de rendre (en utilisant le service de rendu).

Vous pouvez donc simplement le passer en tant que variable à twig (pour cet exemple, c'est le retour d'un Controller):

return [
  ['description' => [
    '#theme' => 'your_theme_hook',
    '#your_variable => $view
  ]
]

dans votre module vous avez besoin d'un hook_theme () pour votre variable:

function hook_theme($existing, $type, $theme, $path) {
  return array(
    'your_theme_hook' => array(
      'variables' => [
        'your_variable' => NULL,
      ]
    )
  )
}

Et enfin dans votre modèle de brindille:

{{ your_variable }}
CliveCleaves
la source
5

J'avais besoin d'obtenir le code HTML d'un bloc personnalisé et je l'ai obtenu en utilisant:

$con = \Drupal\block\BlockViewBuilder::lazyBuilder('bartik_search', 'full');
$d   = \Drupal::service('renderer')->renderPlain($con);

print $d->__toString();
Eugene
la source
1
J'avais besoin de l'ajouter à un tableau de rendu et cela a fonctionné sans __toString().
leymannx
1
Il est important de mentionner qu'un bloc doit au moins être placé dans la région "Blocs désactivés". Ou toute autre région active.
leymannx
1
// You need a block_id! to get it just click configure in the desire block and you'll get url like this /admin/structure/block/manage/bartik_search   the last part of the parameter is the block id
$block = \Drupal\block\Entity\Block::load('bartik_search');
$block_content = \Drupal::entityManager()
  ->getViewBuilder('block')
  ->view($block);

return array('#markup' => \Drupal::service('renderer')->renderRoot($block_content));
Adi
la source
Si possible, vous devez éviter d'utiliser drupal_renderou le service de rendu. drupal_renderest déprécié mais returing un rendu un tableau avec le contenu rendu est assez mauvais, vous devriez retourner à la $block_contentplace, le tableau de rendu peut être modifié avant le rendu réel et vous devriez laisser Drupal faire le rendu autant que possible à la place ou le faire vous-même.
googletorp
Cela ne fonctionnera que si le bloc est déjà placé sur la page via la disposition des blocs.
hugronaphor
1

Fondamentalement, il existe deux types de rendus.

  1. Lorsqu'il existe une instance existante du bloc dans la présentation. le bloc peut être rendu en brindille en utilisant un prétraitement comme

    $ block = Block :: load ('BLOCK_ID'); $ variables ['social_links'] = \ Drupal :: entityTypeManager () -> getViewBuilder ('block') -> view ($ block);

  2. Il n'y a aucune instance ou configuration pour le bloc. Ensuite, dans le préprocesseur, nous devons créer l'instance, construire le bloc puis le rendre

    $ block_manager = \ Drupal :: service ('plugin.manager.block'); $ config = []; $ plugin_block = $ block_manager-> createInstance ('farmjournal_social_sharing', $ config); $ render = $ plugin_block-> build (); $ variables ['farmjournal_social_sharing'] = render ($ render);

Wasim Khan
la source
0

Semble que cela fonctionne pour les blocs de plugins ..

$block = \Drupal\block\Entity\Block::load('some_block_id_3');
  $pluin = $block->getPlugin();
  $build = $pluin->build();
  $build['#weight'] = 4;
  $form['block'] = $build;
Taggart Jensen
la source
-2

Vous obtenez une sortie de bloc:

$block = \Drupal\block\Entity\Block::load ('my_bock_id');
$block_content = \Drupal::entityManager ()->
  getViewBuilder ('block')->
  view ($block);

Et puis vous pouvez renvoyer la sortie de différentes manières:

return array (
    '#type' => 'container',
    'element-content' => $block_content
);

ou:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];
olegiv
la source
\Drupal::service ('renderer')->render ($block_content)peut être fait car drupal_render ($block_content)Cependant ce dernier est déprécié dans Drupal 8.
olegiv
Si possible, vous devez éviter d'utiliser drupal_renderou le service de rendu. drupal_renderest déprécié mais returing un rendu un tableau avec le contenu rendu est assez mauvais, vous devriez retourner à la $block_contentplace, le tableau de rendu peut être modifié avant le rendu réel et vous devriez laisser Drupal faire le rendu autant que possible à la place ou le faire vous-même. Ce que vous retournez doit être rendu à nouveau, ce qui rend le rendu réel inutile
googletorp
-2

Sur la base de mes recherches, vous pouvez baser le code de Comment rendre un bloc par programme dans drupal 8 . Vous pouvez également changer

return array('#markup' => \Drupal::service('renderer')->renderRoot($block_content));

en quelque chose d'aussi simple que:

$output .= \Drupal::service('renderer')->renderRoot($block_content);

pour l'attacher par exemple dans la variable de retour d'une page.

Leolando Tan
la source
Si possible, vous devez éviter d'utiliser drupal_renderou le service de rendu. drupal_renderest déprécié mais returing un rendu un tableau avec le contenu rendu est assez mauvais, vous devriez retourner à la $block_contentplace, le tableau de rendu peut être modifié avant le rendu réel et vous devriez laisser Drupal faire le rendu autant que possible à la place ou le faire vous-même.
googletorp
Tu as raison. Ce n'est pas la solution recommandée et la plus flexible.
Leolando Tan
Votre lien est mort "Comment rendre un bloc ..."
sea26.2