Wie kann ich einen Block programmgesteuert anzeigen?


33

Ich entwickle eine Site mit Drupal 8 Beta-14. Ich habe einen Ansichtsblock mit verschiedenen Begriffen erstellt und möchte ihn jetzt mit Code anzeigen. Wie kann ich es programmatisch anzeigen? Ich habe es in Drupal 7 mit diesem Code gemacht, aber ich bin verwirrt über Drupal 8.

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

Antworten:


69

Es gibt zwei Arten von Blöcken, und die Methode zum Rendern der beiden ist etwas unterschiedlich:

Inhaltsblöcke

Inhaltsblöcke sind Blöcke, die Sie in der Benutzeroberfläche erstellen. Sie ähneln Datenstrukturen, die mit Knoten konfiguriert werden können, mit Feldern usw. Wenn Sie eine dieser Strukturen rendern möchten, können Sie das tun, was Sie normalerweise mit Entitäten tun würden. Laden Sie sie und rendern Sie sie mit dem View Builder:

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

Plugin-Blöcke

Blöcke können auch Plugins sein, die in verschiedenen Modulen definiert sind. Ein Beispiel könnte der Paniermehlblock sein. Wenn Sie diese rendern möchten, müssen Sie den Block-Plugin-Manager verwenden.

$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äten konfigurieren

Gemeinsam für die beiden Typen sind Blöcke. Wenn Sie sie in eine Region einfügen, erstellen Sie eine Konfigurationsentität, die alle Einstellungen für den Block enthält. In einigen Fällen ist es sinnvoller, mit Konfigurationsentitäten umzugehen. Da derselbe Block in mehreren Regionen mit und mit unterschiedlicher Konfiguration platziert werden kann, kann die Verwendung der Blockkonfigurationsentitäten schwieriger werden. Das Schöne ist, dass Sie möglicherweise einen Block mit einer bestimmten Konfiguration rendern möchten. Das Schlechte ist, dass sich die Konfigurations-IDs ändern können, wenn Sie an der Schnittstelle herumspielen, sodass der Code möglicherweise nicht funktioniert, nachdem Benutzer die Blockschnittstelle verwenden dürfen.

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;

2
Die Frage gibt nicht an, ob es um das Rendern einer Blockkonfigurationsentität (eine vorkonfigurierte Blockplatzierung) oder eines Blockplugins mit fester Konfiguration geht. Was Sinn macht, weil dieser Unterschied in 7.x nicht existiert. Dies ist flexibler, da der andere tatsächlich einen bestimmten Block benötigt, der in einem bestimmten Thema und einer bestimmten Region platziert werden muss. Sie sollten jedoch niemals von Hand erstellt werden. Verwenden Sie dazu die createInstance () -Methode des Block-Plug-in-Managers mit der Plug-in-ID, in der Sie auch ein $ configuration-Array bereitstellen können ...
Berdir

2
Vielleicht möchten Sie auch die access () -Methode zuerst aufrufen, falls der Blockzugriff beispielsweise auf eine bestimmte Berechtigung durch diesen Block beschränkt ist. Können Sie Ihre Antwort ein wenig verbessern? Kann dann eine nützliche Ressource werden :)
Berdir

1
@Berdir Es ist schon eine Weile her, aber ich bin endlich dazu gekommen, die Antwort zu verbessern. Bei all den verschiedenen Caching-Vorgängen ist die direkte Verwendung des Plugins wahrscheinlich nur in begrenzten Situationen sinnvoll.
googletorp

4
Der Nachteil bei der Verwendung des Block-Plug-In-Managers createInstance () ist, dass das resultierende Render-Array nicht durch Block-Theming ausgeführt wird, sodass Sie beispielsweise den Block blockname.twig.html nicht verwenden können. Die Alternative besteht darin, einen Block für Ihr Design zu erstellen, diesen jedoch deaktiviert zu lassen. Führen Sie dann in Ihrem Code Folgendes aus: `` $ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('block') -> view ($ block); `` `
Joachim

1
Nö - Noch ein Kaninchenbau. Der Code für den Inhalt blockiert weiße Bildschirme (mit dem berüchtigten "Die Website ist auf einen unerwarteten Fehler gestoßen. Bitte versuchen Sie es später noch einmal.") Der zweite kommt näher - Zeigt jedoch eine kryptische Meldung über den fehlenden Block an oder etwas ... (was nicht der Fall ist) ist nicht wahr, weil ich versuche, ein System zu blockieren (das Powered by Drupal-Ding).
sea26.2

16

Für die Anzeige nur Ihres Blocks in Ihren Vorlagen mit Vorverarbeitung ist der beste Weg

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

Und in Ihrem page.html.twigoder node.html.twigoder xxx.html.twigverwenden Sie Ihre Variable My_region wie folgt:

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

Und im darstellbaren Array (benutzerdefiniertes Modul) durch Beispiel in einen in content () benutzerdefinierten Controller:

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

Verwenden drupal_renderist nicht sinnvoll, da Drupal das Rendern in D8 bereits voraussetzt und dies veraltet ist . Sie sollten \Drupal::service('renderer')->renderRoot()stattdessen verwenden.

Es ist etwas schwer, es ist besser, das Maximum-Area-System zu verwenden und keinen Ladeblock aus dem Vorprozess hinzuzufügen. Im Falle der Verwendung eines Controllers in Ihren Modulen scheint dies eine berechtigte Verwendung zu sein.


Diese Controller-Implementierung ist genau das, wonach ich gesucht habe. Vielen Dank!
Mrweiner

Ich interessiere mich für diese Controller-Implementierung für einen ähnlichen Anwendungsfall, mit dem ich mich befasse. Ich kann jedoch keine Dokumentation zu element-contentEigenschaften in einem Render-Array finden. Wissen Sie, wo es dokumentiert ist?
Eria

Ich weiß nicht warum, kehre \Drupal\block\Entity\Block::loadaber nicht die ganze Zeit einen Block zurück. Es wird nur dann etwas zurückgegeben, wenn der von mir geladene Block in der Ansicht im Blocklayout platziert ist . Wenn es nicht platziert ist, gibt es null zurück.
Arthur Attout

Diese Antwort sollte aktualisiert werden\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman

6

Zusätzlich zur obersten Antwort ... Wenn Sie einen Block aus einer Ansicht rendern möchten, müssen Sie die Dinge möglicherweise etwas anders machen.

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

(Anzeigename zB -> Block_1)

Da wir es an twig übergeben, müssen wir nicht rendern (mit dem Render-Service).

Sie können es also einfach als Variable an twig übergeben (in diesem Beispiel die Rückgabe eines Controllers):

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

In Ihrem Modul benötigen Sie ein hook_theme () für Ihre Variable:

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

Und zum Schluss in Ihrer Zweigvorlage:

{{ your_variable }}

5

Ich musste den HTML-Code eines benutzerdefinierten Blocks abrufen und mit folgendem Befehl abrufen:

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

print $d->__toString();

1
Ich musste es zu einem Render-Array hinzufügen und dort funktionierte es ohne __toString().
Leymannx

1
Wichtig zu erwähnen, dass ein Block mindestens im Bereich "Deaktivierte Blöcke" platziert werden muss. Oder eine andere aktive Region.
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));

Wenn möglich, sollten Sie die Verwendung drupal_renderoder den Render-Service vermeiden . drupal_renderEs ist ziemlich schlecht, ein Array mit dem gerenderten Inhalt wiederherzustellen. Sie sollten $block_contentstattdessen zurückkehren. Das Render-Array kann vor dem eigentlichen Rendern geändert werden, und Sie sollten Drupal das Rendern so weit wie möglich selbst ausführen lassen.
googletorp

Dies funktioniert nur, wenn der Block bereits im Blocklayout auf der Seite platziert ist.
Hugronaphor

1

Grundsätzlich gibt es zwei Arten von Renderings.

  1. Wenn im Layout eine Instanz des Blocks vorhanden ist. Der Block kann mit Preprocess as im Zweig gerendert werden

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

  2. Es gibt keine Instanz oder Konfigurationen für den Block. Dann müssen wir im Präprozessor die Instanz erstellen, den Block erstellen und dann rendern

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


0

Scheint, dass dies für Plugin-Blöcke funktioniert.

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

-2

Sie erhalten eine Blockausgabe:

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

Und dann können Sie die Ausgabe auf verschiedene Arten zurückgeben:

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

oder:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];

\Drupal::service ('renderer')->render ($block_content)drupal_render ($block_content)Dies kann wie folgt geschehen: Letzteres ist in Drupal 8 veraltet.
olegiv

Wenn möglich, sollten Sie die Verwendung drupal_renderoder den Render-Service vermeiden . drupal_renderEs ist ziemlich schlecht, ein Array mit dem gerenderten Inhalt wiederherzustellen. Sie sollten $block_contentstattdessen zurückkehren. Das Render-Array kann vor dem eigentlichen Rendern geändert werden, und Sie sollten Drupal das Rendern so weit wie möglich selbst ausführen lassen. Was Sie zurückgeben, muss erneut gerendert werden, wodurch das eigentliche Rendern sinnlos wird
googletorp

-2

Basierend auf meinen Recherchen könnten Sie den Code aus So rendern Sie einen Block programmgesteuert in Drupal 8 . Sie könnten sich auch ändern

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

in etwas so einfaches wie:

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

um es zum Beispiel an die Rückgabevariable einer Seite anzuhängen.


Wenn möglich, sollten Sie die Verwendung drupal_renderoder den Render-Service vermeiden . drupal_renderEs ist ziemlich schlecht, ein Array mit dem gerenderten Inhalt wiederherzustellen. Sie sollten $block_contentstattdessen zurückkehren. Das Render-Array kann vor dem eigentlichen Rendern geändert werden, und Sie sollten Drupal das Rendern so weit wie möglich selbst ausführen lassen.
googletorp

Du hast recht. Dies ist nicht die empfohlene und flexibelste Lösung.
Leolando Tan

Ihr Link ist tot. "So rendern Sie einen Block ..."
sea26.2
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.