Jak mogę programowo wyświetlić blok?

33

Tworzę witrynę przy użyciu Drupal 8 beta-14. Utworzyłem blok widoku różnych terminów i teraz chcę go wyświetlić za pomocą kodu. Jak mogę wyświetlić programowo? Robiłem to w Drupal 7 przy użyciu tego kodu, ale nie jestem pewien co do Drupala 8.

$block = module_invoke('block', 'block_view', '4');
$text_block = render($block['content']);
rashidkhan
źródło

Odpowiedzi:

69

Istnieją dwa rodzaje bloków, a metoda renderowania tych dwóch jest nieco inna:

Bloki treści

Bloki treści to bloki tworzone w interfejsie. Przypominają one konfigurowalne struktury danych węzłów z polami itp. Jeśli chcesz renderować jedną z nich, możesz zrobić to, co normalnie zrobiłbyś z jednostkami, załadować je i renderować za pomocą kreatora widoków:

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

Bloki wtyczek

Bloki mogą być również wtyczkami zdefiniowanymi w różnych modułach. Przykładem może być blok nawigacyjny. Jeśli chcesz je wyrenderować, musisz użyć menedżera wtyczek blokowych.

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

Konfiguruj encje

Wspólne dla tych dwóch typów są bloki. Po wstawieniu ich do regionu utworzysz element konfiguracji, który ma wszystkie ustawienia bloku. W niektórych przypadkach bardziej użyteczna będzie obsługa encji konfiguracyjnych. Ponieważ ten sam blok może być umieszczony w wielu regionach z inną konfiguracją i może być trudniejszy przy użyciu jednostek konfiguracji bloku. Fajną rzeczą jest to, że możesz chcieć renderować blok z określoną konfiguracją, złą rzeczą jest to, że identyfikatory konfiguracji mogą się zmieniać przez bałagan w interfejsie, więc kod może nie działać po umożliwieniu użytkownikom korzystania z interfejsu bloku.

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;
googletorp
źródło
2
Pytanie nie określa, czy chodzi o renderowanie encji konfiguracji bloku (wstępnie skonfigurowane umieszczenie bloku), czy wtyczki bloku z konfiguracją na stałe. To ma sens, ponieważ ta różnica nie istnieje w 7.x. Jest to bardziej elastyczne, ponieważ druga faktycznie wymaga określonego bloku, który musi być umieszczony w danym temacie i regionie. Jednak nigdy nie należy ich tworzyć ręcznie. Użyj do tego metody createInstance () menedżera wtyczek blokowych z identyfikatorem wtyczki, w którym możesz również podać tablicę konfiguracji $ ...
Berdir
2
Warto też rozważyć najpierw wywołanie metody access () w przypadku, gdy dostęp do bloku jest ograniczony do np. Pewnych uprawnień tego bloku. Czy możesz trochę poprawić swoją odpowiedź? Może wtedy stać się użytecznym zasobem :)
Berdir
1
@Berdir Minęło trochę czasu, ale w końcu udało mi się poprawić odpowiedź. Biorąc pod uwagę różne buforowanie, bezpośrednie użycie wtyczki jest prawdopodobnie przydatne tylko w ograniczonych sytuacjach.
googletorp
4
Wadą korzystania z menedżera wtyczek blokowych createInstance () jest to, że wynikowa tablica renderowania nie jest uruchamiana przez blokowanie tematów, więc nie można na przykład użyć bloku - nazwa_bloku.twig.html. Alternatywą jest utworzenie bloku dla motywu, ale pozostaw go wyłączonego, a następnie w kodzie wykonaj: `` $ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('block') -> view ($ block); ``
joachim
1
Nie - Kolejna nora królika. Kod białych bloków treści (z niesławnym „Witryna napotkała nieoczekiwany błąd. Spróbuj ponownie później.”) Drugi zbliża się - wyświetla jednak tajemniczy komunikat o braku bloku lub coś ... (co nie jest to prawda, ponieważ próbuję bloku systemowego - zasilanego przez drupala).
morze26.2
16

Najlepszym sposobem do wyświetlania tylko bloków w szablonach z wstępnym przetwarzaniem

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

Iw swoim page.html.twiglub node.html.twigczy xxx.html.twigużyć zmiennej My_region takiego:

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

I w tablicy do renderowania (moduł niestandardowy), na przykład, w kontrolerze niestandardowym w 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,
      );
}

Za pomocą drupal_rendernie jest użyteczny, ponieważ Drupal już zakłada renderowanie w D8 i jest to przestarzałe . Zamiast tego powinieneś użyć \Drupal::service('renderer')->renderRoot().

Jest trochę ciężki, lepiej jest użyć systemu maksymalnego obszaru i nie dodaje bloku obciążenia z procesu wstępnego. W przypadku użycia kontrolera w modułach wydaje się to uzasadnione.

woprrr
źródło
Ta implementacja kontrolera jest dokładnie tym, czego szukałem. Dzięki!
Mrweiner
Interesuje mnie ta implementacja kontrolera dla podobnego przypadku użycia, z którym mam do czynienia. Ale nie mogę znaleźć żadnej dokumentacji dotyczącej element-contentwłaściwości w tablicy renderowania. Czy wiesz, gdzie jest to udokumentowane?
Eria
Nie wiem dlaczego, ale \Drupal\block\Entity\Block::loadnie zwraca bloku cały czas. Zwraca coś tylko wtedy, gdy ładowany blok jest umieszczony w widoku w układzie bloku . Jeśli nie jest umieszczony, zwraca null.
Arthur Attout
Ta odpowiedź powinna zostać zaktualizowana w celu użycia\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman
6

Oprócz najważniejszej odpowiedzi ... Jeśli chcesz renderować blok z widoku, być może będziesz musiał zrobić coś nieco inaczej.

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

(nazwa wyświetlana np. -> blok_1)

Ponieważ zamierzamy przekazać go gałązce, nie musimy renderować (używając usługi renderowania).

Możesz więc po prostu przekazać ją jako zmienną do gałązki (w tym przykładzie jest to zwrot kontrolera):

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

w swoim module potrzebujesz hook_theme () dla swojej zmiennej:

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

I wreszcie w szablonie twig:

{{ your_variable }}
CliveCleaves
źródło
5

Musiałem pobrać kod HTML niestandardowego bloku i użyć go:

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

print $d->__toString();
Eugene
źródło
1
Musiałem dodać go do tablicy renderowania i działało bez niego __toString().
leymannx,
1
Ważne jest, aby wspomnieć, że blok musi przynajmniej zostać umieszczony w regionie „Wyłączone bloki”. Lub jakikolwiek inny aktywny 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));
Adi
źródło
Jeśli to możliwe, należy unikać korzystania drupal_renderz usługi renderowania. drupal_renderjest zaniedbany, ale zachowanie renderowania tablicy z renderowaną zawartością jest dość złe, powinieneś $block_contentzamiast tego powrócić , tablica renderowania może zostać zmieniona przed rzeczywistym renderowaniem i powinieneś pozwolić Drupalowi wykonać rendering w miarę możliwości lub zrobić to sam.
googletorp
Działa to tylko wtedy, gdy blok jest już umieszczony na stronie poprzez układ bloku.
hugronaphor
1

Zasadniczo istnieją dwa typy renderów.

  1. Gdy w układzie istnieje instancja bloku. blok może być renderowany w gałązce przy użyciu wstępnego przetwarzania jako

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

  2. Nie ma instancji ani konfiguracji bloku. Następnie w preprocesorze musimy utworzyć instancję, zbudować blok, a następnie go wyrenderować

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

Wasim Khan
źródło
0

Wygląda na to, że działa to w przypadku bloków wtyczek.

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

Otrzymujesz wyjście bloku:

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

Następnie możesz zwrócić dane wyjściowe na różne sposoby:

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

lub:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];
olegiv
źródło
\Drupal::service ('renderer')->render ($block_content)można to zrobić, drupal_render ($block_content)jednak ten ostatni jest przestarzały w Drupal 8.
olegiv
Jeśli to możliwe, należy unikać korzystania drupal_renderz usługi renderowania. drupal_renderjest zaniedbany, ale zachowanie renderowania tablicy z renderowaną zawartością jest dość złe, powinieneś $block_contentzamiast tego powrócić , tablica renderowania może zostać zmieniona przed rzeczywistym renderowaniem i powinieneś pozwolić Drupalowi wykonać rendering w miarę możliwości lub zrobić to sam. To, co
zwrócisz,
-2

Na podstawie moich badań możesz oprzeć kod z Jak renderować blok programowo w Drupal 8 . Możesz także zmienić

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

w coś tak prostego jak:

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

aby dołączyć go na przykład do zmiennej zwrotnej strony.

Leolando Tan
źródło
Jeśli to możliwe, należy unikać korzystania drupal_renderz usługi renderowania. drupal_renderjest zaniedbany, ale zachowanie renderowania tablicy z renderowaną zawartością jest dość złe, powinieneś $block_contentzamiast tego powrócić , tablica renderowania może zostać zmieniona przed rzeczywistym renderowaniem i powinieneś pozwolić Drupalowi wykonać rendering w miarę możliwości lub zrobić to sam.
googletorp
Masz rację. To nie jest zalecane i najbardziej elastyczne rozwiązanie.
Leolando Tan 30.01.16
Twój link jest martwy „Jak wyrenderować blok ...”
morze26.2