¿Cómo puedo mostrar programáticamente un bloque?

33

Estoy desarrollando un sitio usando Drupal 8 beta-14. He creado un bloque de vista de diferentes términos y ahora quiero mostrarlo usando código. ¿Cómo puedo mostrarlo programáticamente? Solía ​​hacerlo en Drupal 7 usando este código, pero estoy confundido acerca de Drupal 8.

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

Respuestas:

69

Hay dos tipos de bloques, y el método para representarlos es un poco diferente:

Bloques de contenido

Los bloques de contenido son bloques que crea en la interfaz. Se parecen mucho a las estructuras de datos configurables de los nodos, con campos, etc. Si desea representar uno de estos, puede hacer lo que normalmente haría con las entidades, cargarlas y representarlas con el generador 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;

Bloques de complementos

Los bloques también pueden ser complementos, definidos en varios módulos. Un ejemplo podría ser el bloque de migas de pan. Si desea renderizarlos, deberá usar el administrador de complementos de bloque.

$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 configuración

Compartidos para los dos tipos son bloques, es decir, una vez que los inserte en una región, creará una entidad de configuración que tiene todas las configuraciones para el bloque. En algunos casos será más útil manejar entidades de configuración. Dado que el mismo bloque se puede colocar en múltiples regiones con y con una configuración diferente, puede ser más complicado usar las entidades de configuración de bloque. Lo bueno es que es posible que desee renderizar un bloque con una configuración específica, lo malo es que los identificadores de configuración pueden cambiar jugando con la interfaz, por lo que el código podría no funcionar después de permitir que los usuarios usen la interfaz de bloque.

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;
googletorp
fuente
2
La pregunta no especifica si se trata de representar una entidad de configuración de bloque (una ubicación de bloque preconfigurada) o un complemento de bloque con configuración codificada. Lo cual tiene sentido porque esa diferencia no existe en 7.x. Esto es más flexible porque el otro realmente requiere un bloque específico que debe colocarse en un tema y región determinados. Sin embargo, nunca debe crearlos a mano. Use el método createInstance () del administrador de complementos de bloque para eso con la ID del complemento, donde también puede proporcionar una matriz de configuración $ ...
Berdir
2
Además, es posible que desee considerar llamar primero al método access () en caso de que el acceso al bloque esté restringido, por ejemplo, a un cierto permiso de ese bloque. ¿Puedes mejorar tu respuesta un poco en eso? Puede convertirse en un recurso útil entonces :)
Berdir
1
@ Berdir Ha pasado un tiempo, pero finalmente pude mejorar la respuesta. Con todos los diversos cachés en curso, el uso del complemento directamente probablemente solo sea útil en situaciones limitadas.
googletorp
44
La desventaja de usar el administrador de complementos de bloque createInstance () es que la matriz de renderización resultante no se ejecuta a través de la temática de bloque, por lo que no puede usar el bloque - blockname.twig.html, por ejemplo. La alternativa es crear un bloque para su tema, pero déjelo deshabilitado, y luego en su código haga: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('bloque') -> vista ($ bloque); `` `
joachim
1
No, otra madriguera de conejo. El código para el contenido bloquea las pantallas blancas (con el infame "El sitio web encontró un error inesperado. Inténtalo de nuevo más tarde"). El segundo se acerca - Pero muestra un mensaje críptico sobre la falta del bloque o algo ... (que no es No es cierto porque estoy intentando un bloqueo del sistema, el que funciona con drupal).
mar26.2
16

Para mostrar solo su bloque en sus plantillas con preproceso, la mejor manera es

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

Y en su page.html.twigo node.html.twigo xxx.html.twigutilizar la variable de My_region como esto:

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

Y en una matriz renderizable (módulo personalizado), por ejemplo, en un controlador personalizado en contenido ():

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,
      );
}

Utilizando drupal_renderno es útil ya que Drupal ya asume el renderizado en D8 y esto está en desuso . Deberías usar \Drupal::service('renderer')->renderRoot()en su lugar.

Es un poco pesado, es mejor usar el sistema de área máxima y no agrega bloque de carga desde el preproceso. En el caso de usar un controlador en sus módulos, este parece ser un uso justificado.

woprrr
fuente
Esta implementación del controlador es exactamente lo que estaba buscando. ¡Gracias!
Mrweiner
Estoy interesado en esta implementación de controlador para un caso de uso similar con el que estoy tratando. Pero no puedo encontrar ninguna documentación sobre la element-contentpropiedad en una matriz de renderizado. ¿Sabes dónde está documentado?
Eria
No sé por qué, pero \Drupal\block\Entity\Block::loadno devuelve un bloque todo el tiempo. Solo devuelve algo si el bloque que cargo se coloca dentro de la vista en el diseño de bloque . Si no se coloca, devuelve nulo.
Arthur Attout
Esta respuesta debe actualizarse para usar\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman
6

Además de la respuesta principal ... Si desea representar un bloque desde una vista, es posible que tenga que hacer las cosas de manera un poco diferente.

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

(nombre para mostrar, por ejemplo, -> bloque_1)

Como lo vamos a pasar a twig, no necesitamos renderizar (usando el servicio de render).

Por lo tanto, puede pasarlo como una variable a twig (para este ejemplo, es el retorno de un Controlador):

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

en su módulo necesita un hook_theme () para su variable:

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

Y finalmente en tu plantilla de ramita:

{{ your_variable }}
CliveCleaves
fuente
5

Necesitaba obtener el HTML de un bloque personalizado y lo obtuve usando:

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

print $d->__toString();
Eugene
fuente
1
Necesitaba agregarlo a una matriz de renderizado y allí funcionó sin él __toString().
leymannx
1
Es importante mencionar que al menos un bloque debe colocarse en la región "Bloques deshabilitados". O cualquier otra región activa.
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
fuente
Si es posible, debe evitar usar drupal_rendero el servicio de procesamiento. drupal_renderestá depurado, pero devolver un conjunto de renderizado con el contenido renderizado es bastante malo, en su $block_contentlugar, debe volver , el conjunto de renderizado puede modificarse antes del render real y debe dejar que Drupal haga el renderizado tanto como sea posible o hacerlo usted mismo.
googletorp
Esto funcionará solo si el bloque ya está colocado en la página a través del diseño del bloque.
hugronaphor
1

Básicamente, hay dos tipos de renders.

  1. Cuando hay una instancia existente del bloque en el diseño. el bloque se puede representar en ramita usando el preproceso como

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

  2. No hay instancias o configuraciones para el bloque. Luego, en el preprocesador, necesitamos crear la instancia, construir el bloque y luego renderizarlo

    $ 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
fuente
0

Parece que esto funciona para bloques de complementos.

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

Obtiene salida de bloque:

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

Y luego puede devolver la salida de diferentes maneras:

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

o:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];
olegiv
fuente
\Drupal::service ('renderer')->render ($block_content)puede hacerse como drupal_render ($block_content)Sin embargo, este último está en desuso en Drupal 8.
olegiv
Si es posible, debe evitar usar drupal_rendero el servicio de procesamiento. drupal_renderestá depurado, pero devolver un conjunto de renderizado con el contenido renderizado es bastante malo, en su $block_contentlugar, debe volver , el conjunto de renderizado puede modificarse antes del render real y debe dejar que Drupal haga el renderizado tanto como sea posible o hacerlo usted mismo. Lo que devuelve debe procesarse nuevamente, lo que hace que la representación real no
tenga
-2

Según mi investigación, podría basar el código de Cómo representar un bloque mediante programación en drupal 8 . También podrías cambiar

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

en algo tan simple como:

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

para adjuntarlo, por ejemplo, a la variable de retorno de una página.

Leolando Tan
fuente
Si es posible, debe evitar usar drupal_rendero el servicio de procesamiento. drupal_renderestá depurado, pero devolver un conjunto de renderizado con el contenido renderizado es bastante malo, en su $block_contentlugar, debe volver , el conjunto de renderizado puede modificarse antes del render real y debe dejar que Drupal haga el renderizado tanto como sea posible o hacerlo usted mismo.
googletorp
Tienes razón. Esta no es la solución recomendada y más flexible.
Leolando Tan
Su enlace está muerto "Cómo representar un bloque ..."
sea26.2