如何以编程方式显示块?


33

我正在使用Drupal 8 beta-14开发一个站点。我创建了一个不同术语的视图块,现在我想使用代码来显示它。如何以编程方式显示它?我曾经在Drupal 7中使用此代码来做,但是我对Drupal 8感到困惑。

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

Answers:


69

有两种类型的块,呈现两种块的方法略有不同:

内容块

内容块是您在界面中创建的块。它们非常类似于节点可配置的数据结构,以及字段等。如果要呈现其中之一,则可以执行与实体一样的常规操作,加载它们并使用视图构建器呈现它们:

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

插件块

块也可以是插件,可以在各种模块中定义。一个示例可以是面包屑块。如果要渲染这些,则需要使用块插件管理器。

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

配置实体

两种类型共享的是块,即一旦将它们插入一个区域,您将创建一个配置实体,其中包含该块的所有设置。在某些情况下,处理配置实体会更加有用。由于同一块可以通过不同的配置放置在多个区域中,因此使用块配置实体会变得更加棘手。令人高兴的是,您可能希望使用特定的配置来呈现块,而糟糕的是,可以通过弄乱接口来更改配置ID,因此在允许用户使用块接口后,代码最终可能无法正常工作。

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

2
该问题未指定是要渲染块配置实体(预先配置的块放置)还是具有硬编码配置的块插件。这是有道理的,因为在7.x中不存在这种差异。这是更灵活的,因为另一个实际上需要一个需要放置在给定主题和区域中的特定块。但是,永远不要手工创建它们。使用带有插件ID的块插件管理器的createInstance()方法,您还可以在其中提供$ configuration数组...
Berdir

2
另外,在块访问被限制为例如该块具有一定权限的情况下,您可能需要考虑先调用access()方法。您能否对此有所改善?然后可以成为有用的资源:)
Berdir 2015年

1
@Berdir已经有一段时间了,但是我终于可以改善答案了。随着所有各种缓存的进行,直接使用插件可能仅在有限的情况下有用。
googletorp

4
使用块插件管理器createInstance()的不利之处在于,生成的渲染数组未通过块主题运行,因此,例如,您将无法使用块--blockname.twig.html。另一种方法是为您的主题创建一个块,但将其禁用,然后在您的代码中执行:```$ block = \ Drupal \ block \ Entity \ Block :: load('myblock'); $ build = \ Drupal :: entityManager()-> getViewBuilder('block')-> view($ block); ```
joachim

1
没有-另一个兔子洞。内容块白屏的代码(臭名昭著的“该网站遇到意外错误。请稍后重试。”)第二个代码越来越近-但是显示有关该块丢失或某些内容的神秘消息...(不是是不正确的,因为我正在尝试系统块-由drupal事物提供动力)。
sea26.2

16

为了只显示模板中带有预处理的块,最好的方法是

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

然后在您的page.html.twigor node.html.twigxxx.html.twig使用变量My_region中,如下所示:

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

并在可渲染数组(自定义模块)中通过示例转换为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,
      );
}

使用 drupal_render这是没有用的,因为Drupal已经假定在D8中进行渲染,因此已弃用。您应该\Drupal::service('renderer')->renderRoot()改用。

它有点重,最好使用最大面积系统,并且不要在预处理过程中添加负载块。在模块中使用控制器的情况下,这似乎是合理的用法。


该控制器实现正是我想要的。谢谢!
Mrweiner '18

我对我正在处理的类似用例的此控制器实现感兴趣。但是我element-content在渲染数组中找不到有关属性的任何文档。您知道在哪里记录吗?
伊里亚(Eria)

我不知道为什么,但是\Drupal\block\Entity\Block::load不会一直返回一个块。仅当我加载的块以块布局放置在视图中时,它才会返回某些内容。如果未放置,则返回null。
亚瑟·阿特特

该答案应更新为使用\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman,

6

除了最重要的答案以外...如果要从视图中渲染图块,则可能必须做些不同的事情。

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

(显示名称,例如-> block_1)

由于我们将其传递给树枝,因此不需要渲染(使用渲染服务)。

因此,您可以将其作为变量传递给树枝(在此示例中,它是控制器的返回):

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

在模块中,您需要为变量添加一个hook_theme():

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

最后在您的树枝模板中:

{{ your_variable }}

5

我需要获取自定义块的HTML并使用以下代码获取它:

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

print $d->__toString();

1
我需要将其添加到渲染数组,并且没有它就可以工作__toString()
leymannx '16

1
值得一提的是,至少需要将一个块放置在“禁用的块”区域中。或任何其他活动区域。
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));

如果可能,应避免使用drupal_render或渲染服务。drupal_render被废弃,但是用渲染的内容重现一个渲染数组是很糟糕的,您应该返回$block_content,可以在实际渲染之前更改渲染数组,并且应该让Drupal尽可能多地渲染渲染,或者自己做。
googletorp

仅当通过块布局将块放置在页面上时,这才起作用。
hugronaphor

1

基本上,有两种类型的渲染。

  1. 布局中存在该块的现有实例时。可以使用预处理将块渲染为树枝

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

  2. 该块没有实例或配置。然后在预处理器中,我们需要创建实例,构建块,然后渲染它

    $ 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

似乎这适用于插件块..

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

-2

您将获得块输出:

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

然后您可能会以不同的方式返回输出:

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

要么:

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

\Drupal::service ('renderer')->render ($block_content)可以进行作为drupal_render ($block_content)然而后者在Drupal 8.弃用
olegiv

如果可能,应避免使用drupal_render或渲染服务。drupal_render被废弃,但是用渲染的内容重现一个渲染数组是很糟糕的,您应该返回$block_content,可以在实际渲染之前更改渲染数组,并且应该让Drupal尽可能多地渲染渲染,或者自己做。您返回的内容需要再次渲染,这使实际渲染毫无意义
googletorp

-2

根据我的研究,您可以基于如何在drupal 8中以编程方式渲染块中的代码。你也可以改变

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

变成简单的东西:

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

例如将其附加到页面的返回变量中。


如果可能,应避免使用drupal_render或渲染服务。drupal_render被废弃,但是用渲染的内容重现一个渲染数组是很糟糕的,您应该返回$block_content,可以在实际渲染之前更改渲染数组,并且应该让Drupal尽可能多地渲染渲染,或者自己做。
googletorp

你是对的。这不是推荐的也是最灵活的解决方案。
Leolando Tan

您的链接已死“如何渲染块...”
sea26.2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.