ฉันจะแสดงบล็อกโดยทางโปรแกรมได้อย่างไร


33

ฉันกำลังพัฒนาเว็บไซต์โดยใช้ Drupal 8 beta-14 ฉันได้สร้างบล็อคมุมมองของคำต่างๆและตอนนี้ฉันต้องการที่จะแสดงมันโดยใช้รหัส ฉันจะแสดงมันแบบเป็นโปรแกรมได้อย่างไร? ฉันเคยทำมันใน Drupal 7 โดยใช้รหัสนี้ แต่ฉันสับสนเกี่ยวกับ Drupal 8

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

คำตอบ:


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;

บล็อกปลั๊กอิน

บล็อกยังสามารถเป็นปลั๊กอินที่กำหนดในโมดูลต่าง ๆ ตัวอย่างอาจเป็น breadcrumb block หากคุณต้องการแสดงผลเหล่านี้คุณจะต้องใช้ตัวจัดการปลั๊กอินบล็อก

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

กำหนดค่าเอนทิตี

ที่ใช้ร่วมกันสำหรับทั้งสองประเภทคือบล็อกคือเมื่อคุณแทรกในพื้นที่คุณจะสร้างเอนทิตีการกำหนดค่าที่มีการตั้งค่าทั้งหมดสำหรับบล็อก ในบางกรณีมันจะมีประโยชน์มากกว่าการจัดการเอนทิตี config เนื่องจากบล็อกเดียวกันสามารถวางในหลายภูมิภาคด้วยและด้วยการกำหนดค่าที่แตกต่างกันจึงสามารถใช้เลเยอร์ที่ซับซ้อนมากขึ้นโดยใช้เอนทิตีการตั้งค่าบล็อก สิ่งที่ดีคือคุณอาจต้องการแสดงผลบล็อกด้วยการกำหนดค่าเฉพาะสิ่งที่ไม่ดีคือรหัสการตั้งค่าสามารถเปลี่ยนแปลงได้โดยการยุ่งกับอินเทอร์เฟซดังนั้นรหัสอาจจบลงไม่ทำงานหลังจากให้ผู้ใช้ใช้อินเตอร์เฟสบล็อก

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

2
คำถามไม่ได้ระบุว่าเป็นเรื่องเกี่ยวกับการแสดงเอนทิตีการกำหนดค่าบล็อก (ตำแหน่งบล็อกที่กำหนดไว้ล่วงหน้า) หรือปลั๊กอินบล็อกที่มีการกำหนดค่าฮาร์ดโค้ด ซึ่งสมเหตุสมผลเนื่องจากความแตกต่างนั้นไม่มีอยู่ใน 7.x สิ่งนี้มีความยืดหยุ่นมากขึ้นเพราะอีกอันหนึ่งจริง ๆ แล้วต้องการบล็อกที่เฉพาะเจาะจงซึ่งจำเป็นต้องวางในธีมและภูมิภาคที่กำหนด อย่างไรก็ตามคุณไม่ควรสร้างด้วยมือ ใช้ CreateInstance วิธี () ผู้จัดการปลั๊กอินบล็อกที่มีรหัสปลั๊กอินที่คุณยังสามารถให้การกำหนดค่าอาร์เรย์ $ ...
Berdir

2
นอกจากนี้คุณอาจต้องการพิจารณาเรียกวิธีการเข้าถึง () ก่อนในกรณีที่การเข้าถึงบล็อกถูก จำกัด เช่นได้รับอนุญาตจากบล็อกนั้น คุณช่วยปรับปรุงคำตอบของคุณสักหน่อยได้ไหม? สามารถกลายเป็นทรัพยากรที่มีประโยชน์ได้แล้ว :)
Berdir

1
@Berdir ไม่นานมานี้ แต่ในที่สุดฉันก็ได้รับการปรับปรุงคำตอบ ด้วยการแคชต่าง ๆ ที่เกิดขึ้นการใช้ปลั๊กอินโดยตรงอาจเป็นประโยชน์เฉพาะในสถานการณ์ที่ จำกัด
googletorp

4
ข้อเสียของการใช้ block plugin manager createInstance () คืออาร์เรย์การเรนเดอร์ที่ได้รับผลจะไม่ถูกเรียกใช้ผ่านการบล็อกแบบบล็อกดังนั้นคุณจึงไม่สามารถใช้ block - blockname.twig.html เป็นต้น ทางเลือกคือการสร้างบล็อกสำหรับธีมของคุณ แต่ปล่อยให้มันปิดการใช้งานและจากนั้นในรหัสของคุณ: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('บล็อก') -> ดู ($ block); `` `
2559

1
Nope - รูกระต่ายอีกอัน รหัสสำหรับหน้าจอสีขาวของบล็อกเนื้อหา (ที่มีชื่อเสีย "เว็บไซต์พบข้อผิดพลาดที่ไม่คาดคิดโปรดลองอีกครั้งในภายหลัง") หน้าจอที่สองเข้ามาใกล้มากขึ้น - แต่แสดงข้อความที่เป็นความลับเกี่ยวกับบล็อกที่หายไปหรือบางอย่าง ... ไม่จริงเพราะฉันพยายามบล็อกระบบ - สิ่งที่ขับเคลื่อนโดยสิ่ง drupal)
sea26.2

16

สำหรับแสดงเฉพาะบล็อกของคุณในเทมเพลตที่มี preprocess วิธีที่ดีที่สุดคือ

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

และในpage.html.twigหรือnode.html.twigหรือxxx.html.twigใช้ตัวแปร My_region ของคุณเช่นนี้:

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

และในอาเรย์ที่สามารถเรนเดอร์ (โมดูลที่กำหนดเอง) โดยตัวอย่างลงในคอนโทรลเลอร์ที่กำหนดเองในเนื้อหา ():

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()แทน

มันหนักไปหน่อยมันจะดีกว่าถ้าใช้ระบบพื้นที่สูงสุดและไม่เพิ่ม load block จาก preprocess ในกรณีของการใช้คอนโทรลเลอร์ในโมดูลของคุณสิ่งนี้ดูเหมือนว่าเป็นการใช้ที่สมเหตุสมผล


การติดตั้งคอนโทรลเลอร์นี้เป็นสิ่งที่ฉันกำลังมองหา ขอบคุณ!
Mrweiner

ฉันสนใจที่จะติดตั้งคอนโทรลเลอร์นี้สำหรับกรณีการใช้งานที่คล้ายกันที่ฉันกำลังทำอยู่ แต่ฉันไม่พบเอกสารเกี่ยวกับelement-contentคุณสมบัติในอาร์เรย์เรนเดอร์ คุณรู้หรือไม่ว่าเอกสารอยู่ที่ไหน
Eria

ฉันไม่รู้ว่าทำไม แต่\Drupal\block\Entity\Block::loadไม่คืนบล็อกตลอดเวลา มันส่งกลับเฉพาะบางสิ่งบางอย่างถ้าโหลดบล็อกผมถูกวางไว้ในมุมมองในรูปแบบบล็อก หากไม่มีการวางไว้ก็จะคืนค่าว่าง
Arthur Attout

คำตอบนี้ควรได้รับการอัพเดทให้ใช้\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

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. เมื่อมีอินสแตนซ์ที่มีอยู่ของบล็อกในเค้าโครง บล็อกสามารถแสดงผลในกิ่งไม้โดยใช้ preprocess เป็น

    $ block = Block :: load ('BLOCK_ID'); $ ตัวแปร ['social_links'] = \ Drupal :: entityTypeManager () -> getViewBuilder ('บล็อก') -> ดู ($ block);

  2. ไม่มีอินสแตนซ์หรือการกำหนดค่าสำหรับบล็อก จากนั้นในพรีโปรเซสเซอร์เราจำเป็นต้องสร้างอินสแตนซ์สร้างบล็อกแล้วสร้างมันขึ้นมา

    $ block_manager = \ Drupal :: service ('plugin.manager.block'); $ config = []; $ plugin_block = $ block_manager-> createInstance ('farmjournal_social_sharing', $ config); $ render = $ plugin_block-> build (); $ ตัวแปร ['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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.