ブロックプラグインを含むカスタムモジュールがあります。
class SliderBlock extends BlockBase {
public function build() {
$build = [];
$build['#theme'] = 'slider_block';
return $build;
}
}
ブロック内に「スライド」タイプのノードのリストをレンダリングしたい(最終的にはカスタムスライダー機能になります)
function mymodule_theme() {
return [
'slides_block' => [
'variables' => [
'slides' => get_slides(),
],
],
];
}
function get_slides() {
// Load all slides nodes.
$nids = \Drupal::entityQuery('node')
->condition('type','slides')
->condition('status','1') // Only published slides nodes.
->execute();
$nodes = \Drupal\node\Entity\Node::loadMultiple($nids);
return $nodes;
}
そして、テンプレートのそれぞれをループして、必要なマークアップを取得します。
{# markup for slider here #}
{% for slide in slides %}
<p>{{ slide.label }}</p>
{% endfor %}
上記のテンプレートは、各スライドノードのタイトルフィールドを示しています。問題は、スライドノードを非公開にした場合、キャッシュをクリアしない限りマークアップが更新されないことです。
これはキャッシュの問題のように聞こえるので、Googleの検索ミッションを調べて、ブロックのキャッシュを無効にする一連の方法を発見しました。匿名ユーザーやその他の場合、どれも機能しないようです:
// Unsuccessful:
public function getCacheMaxAge() {
return 0;
}
// Unsuccessful:
$build['#cache'] = [
'max-age' => 0,
];
私が知る限り、キャッシュコンテキストを調べましたが、「ノード」ベースのキャッシュコンテキストはありませんでした。 「スライド」タイプの特定のノードのIDがわからないため、それらを正しく理解していれば、キャッシュタグは役に立ちません。
このブロックのキャッシュを無効にしたいだけです。このブロックは特定のページでのみレンダリングされるので、モジュールのルートymlファイルを使用してそのページのキャッシュを無効にすることができます(私は正しいですか)。ただし、1つのブロックのためにページ全体を無効にするのは間違っています。
これを解決する正しい方法は何ですか?そしてその結論に到達するための方法論は何ですか?
注:ビューを使用してノードを収集できますが、ビューのマークアップをカスタマイズするのはより困難です。
@Clive コメント のように、ノードリストキャッシュタグが必要です。
(hook_theme()ではなく)ビルド配列でテンプレートを呼び出すときに、スライドとキャッシュタグを配置します。このフックは、モジュールをインストールするときにのみ呼び出されます。
class SliderBlock extends BlockBase {
public function build() {
$build = [
'#theme' => 'slider_block',
'#slides' => getSlides(),
'#cache' => ['tags' => ['node_list']],
];
return $build;
}
}
Drupal 8.9.xに更新したら、コードにTODOアノテーションを入れて、リストタグをコンテンツタイプ固有のnode_list:slides
に変更します。この変更レコードを参照してください。 ENTITY_TYPE_list:BUNDLEキャッシュタグを追加しました。
@Cliveと@leymannxのコメントで述べたように、キャッシュタグを使用してジョブを実行する必要があります。問題は、ノードがテーマフックによって読み込まれているため、現在のアプローチが難しいことです。コードをリファクタリングし、ノードをブロックでロードするようにすれば、Drupalの方法がよりクリーンになり、テーマフックがデータの準備とレンダリングに集中できるようになります。あなたのコードは次のようになる可能性があります(依存性注入は意図的に省略されています、これについて詳しく読んでください ここ ):
SliderBlock.php
class SliderBlock extends BlockBase {
private $slides;
public function build() {
$this->slides = $this->getSlides();
if (empty($this->slides)) {
// Feel free to change to your use case when
// no slides available.
// Keep in mind that any non-empty render array
// could/would be cached.
return [];
}
$build = [];
$build['#theme'] = 'slider_block';
$build['#slides'] = $this->slides;
return $build;
}
function getSlides() {
// Load all slides nodes.
$nids = \Drupal::entityQuery('node')
->condition('type','slides')
->condition('status','1') // Only published slides nodes.
->execute();
return \Drupal\node\Entity\Node::loadMultiple($nids);
}
public function getCacheTags() {
$cache_tags = parent::getCacheTags();
$cache_tags[] = 'block:' . $this->getDerivativeId();
if (empty($this->slides)) {
return $cache_tags;
}
$node_cache_tags = [];
foreach ($this->slides as $node) {
$node_cache_tags[] = $node->getCacheTags();
}
$node_cache_tags = array_merge([], ...$node_cache_tags);
$cache_tags = \Drupal\Core\Cache\Cache::mergeTags($cache_tags, $node_cache_tags);
return $cache_tags;
}
}
...a.k.aスプレッド演算子と、なぜ私がそのようなタグをマージしたのかについて懸念がある場合は、 この投稿 を確認してください。
mymodule.module
function mymodule_theme() {
return [
'slides_block' => [
'variables' => [
'slides' => NULL,
],
],
];
}
また、ブロックキャッシュタグについて この投稿 も確認してください。