Como posso exibir programaticamente um bloco?

33

Estou desenvolvendo um site usando o Drupal 8 beta-14. Eu criei um bloco de exibição de termos diferentes e agora quero exibi-lo usando o código. Como posso exibi-lo programaticamente? Eu costumava fazer isso no Drupal 7 usando esse código, mas estou confuso sobre o Drupal 8.

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

Respostas:

69

Existem dois tipos de blocos, e o método para renderizar os dois é um pouco diferente:

Blocos de Conteúdo

Blocos de conteúdo são blocos criados na interface. Eles são muito parecidos com as estruturas de dados configuráveis ​​dos nós, com campos etc. Se você deseja renderizar uma delas, pode fazer o que normalmente faria com entidades, carregá-las e renderizá-las com o construtor de vistas:

$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;

Blocos de plug-in

Os blocos também podem ser plugins, definidos em vários módulos. Um exemplo pode ser o bloco de trilha de navegação. Se você deseja renderizá-las, precisará usar o gerenciador de plug-ins de bloco.

$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;

Entidades de configuração

Os blocos compartilhados para os dois tipos são: depois que você os inserir em uma região, você criará uma entidade de configuração que possui todas as configurações para o bloco. Em alguns casos, será mais útil lidar com entidades de configuração. Como o mesmo bloco pode ser colocado em várias regiões com e com configurações diferentes, pode ficar mais complicado usando as entidades de configuração do bloco. O bom é que você pode renderizar um bloco com uma configuração específica, o ruim é que os IDs de configuração podem mudar ao mexer na interface, portanto, o código pode não funcionar depois de permitir que os usuários usem a interface do bloco.

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;
googletorp
fonte
2
A pergunta não especifica se é sobre renderizar uma entidade de configuração de bloco (um posicionamento de bloco pré-configurado) ou um plug-in de bloco com configuração codificada. O que faz sentido, porque essa diferença não existe no 7.x. Isso é mais flexível porque o outro realmente requer um bloco específico que precisa ser colocado em um determinado tema e região. No entanto, você nunca deve criá-los manualmente. Use o método createInstance do gerente bloco de plug-in () para que, com o ID plugin, onde você também pode fornecer um array $ configuração ...
Berdir
2
Além disso, convém chamar o método access () primeiro, caso o acesso ao bloco seja restrito a, por exemplo, uma certa permissão desse bloco. Você pode melhorar um pouco sua resposta? Pode tornar-se um recurso útil então :)
Berdir
1
@Berdir Já faz um tempo, mas finalmente consegui melhorar a resposta. Com todos os vários caches em andamento, o uso direto do plug-in provavelmente é útil apenas em situações limitadas.
googletorp
4
A desvantagem de usar o gerenciador de plug-ins de bloco createInstance () é que a matriz de renderização resultante não é executada através da temática do bloco, portanto você não pode usar o bloco - blockname.twig.html, por exemplo. A alternativa é criar um bloco para o seu tema, mas deixe-o desativado e, em seu código, faça: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('bloco') -> exibição ($ bloco); ``
joachim
1
Não - Outra toca de coelho. O código para as telas brancas do bloco de conteúdo (com o infame "O site encontrou um erro inesperado. Tente novamente mais tarde.") O segundo se aproxima - mas exibe uma mensagem enigmática sobre a falta do bloco ou algo assim ... (que não é é verdade porque estou tentando um bloco de sistema - o sistema powered by drupal).
sea26.2
16

Para exibir apenas seu bloco em seus modelos com pré-processamento, a melhor maneira é

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

E no seu page.html.twigou node.html.twigou xxx.html.twiguse sua variável My_region assim:

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

E na matriz renderizável (módulo personalizado), por exemplo, em um controlador personalizado em 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,
      );
}

Usando drupal_rendernão é útil, pois o Drupal já assume a renderização em D8 e isso foi preterido . Você deve usar em seu \Drupal::service('renderer')->renderRoot()lugar.

É um pouco pesado, é melhor usar o sistema de área máxima e não adiciona bloco de carga do pré-processo. No caso de usar um controlador em seus módulos, isso parece um uso justificado.

woprrr
fonte
Essa implementação do controlador é exatamente o que eu estava procurando. Obrigado!
Mrweiner
Estou interessado nesta implementação de controlador para um caso de uso semelhante com o qual estou lidando. Mas não consigo encontrar nenhuma documentação sobre element-contentpropriedade em uma matriz de renderização. Você sabe onde está documentado?
Eria
Não sei por que, mas \Drupal\block\Entity\Block::loadnão retorna um bloco o tempo todo. Ele só retorna algo se o bloco que eu carrego é colocado dentro da visualização no layout do bloco . Se não for colocado, ele retornará nulo.
Arthur Attout
Esta resposta deve ser atualizada para uso\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman
6

Além da resposta principal ... Se você deseja renderizar um bloco de uma exibição, talvez seja necessário fazer as coisas de maneira um pouco diferente.

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

(nome de exibição, por exemplo - -> bloco_1)

Como vamos passar para o galho, não precisamos renderizar (usando o serviço de renderização).

Então você pode simplesmente passá-lo como uma variável para galho (neste exemplo, é o retorno de um Controller):

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

no seu módulo, você precisa de um hook_theme () para sua variável:

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

E, finalmente, no seu modelo de galho:

{{ your_variable }}
CliveCleaves
fonte
5

Eu precisava obter o HTML de um bloco personalizado e obtê-lo usando:

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

print $d->__toString();
Eugene
fonte
1
Eu precisava adicioná-lo a uma matriz de renderização e lá funcionou sem __toString().
Leymannx
1
Importante mencionar que pelo menos um bloco precisa ser colocado na região "Blocos desabilitados". Ou qualquer outra região ativa.
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
fonte
Se possível, evite usar drupal_renderou o serviço de renderização. drupal_renderé depreciado, mas returing uma renderização de uma matriz com o conteúdo renderizado é muito ruim; você deve retornar $block_content, a matriz de renderização pode ser alterada antes da renderização real e você deve permitir que o Drupal faça a renderização o máximo possível ou faça você mesmo.
googletorp
Isso funcionará apenas se o bloco já estiver colocado na página através do layout do bloco.
precisa saber é o seguinte
1

Basicamente, existem dois tipos de renderizações.

  1. Quando existe uma instância existente do bloco no layout. o bloco pode ser renderizado em galho usando pré-processo como

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

  2. Não há instância ou configurações para o bloco. Em seguida, no pré-processador, precisamos criar a instância, criar o bloco e renderizá-lo

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

Wasim Khan
fonte
0

Parece que isso funciona para blocos 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
fonte
-2

Você obtém a saída do bloco:

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

E então você pode retornar a saída de diferentes maneiras:

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

ou:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];
olegiv
fonte
\Drupal::service ('renderer')->render ($block_content)pode ser feito como drupal_render ($block_content)No entanto, o último é preterido no Drupal 8.
olegiv
Se possível, evite usar drupal_renderou o serviço de renderização. drupal_renderé depreciado, mas returing uma renderização de uma matriz com o conteúdo renderizado é muito ruim; você deve retornar $block_content, a matriz de renderização pode ser alterada antes da renderização real e você deve permitir que o Drupal faça a renderização o máximo possível ou faça você mesmo. O que você retorna precisa ser renderizado novamente, o que torna a renderização real inútil
googletorp
-2

Com base em minha pesquisa, você pode basear o código de Como renderizar um bloco programaticamente no drupal 8 . Você também pode mudar

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

em algo tão simples como:

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

para anexá-lo, por exemplo, à variável de retorno de uma página.

Leolando Tan
fonte
Se possível, evite usar drupal_renderou o serviço de renderização. drupal_renderé depreciado, mas returing uma renderização de uma matriz com o conteúdo renderizado é muito ruim; você deve retornar $block_content, a matriz de renderização pode ser alterada antes da renderização real e você deve permitir que o Drupal faça a renderização o máximo possível ou faça você mesmo.
googletorp
Você está certo. Esta não é a solução recomendada e mais flexível.
Leolando Tan
O seu link está morto "Como renderizar um bloco ..."
sea26.2 09/02