diff --git a/docs/cheat-sheet.md b/docs/cheat-sheet.md index 036e974..9b304c4 100644 --- a/docs/cheat-sheet.md +++ b/docs/cheat-sheet.md @@ -386,6 +386,14 @@ ensure that cache metadata are bubbled up. {{ content.field_media|cache_metadata }} ``` +## Conditions from context for access to render arrays +The system that controls the visibility of blocks can be used to evaluate +if a condition is fullfilled. Set the `#access` key to a render array to control visibility. +```twig +{# Display content only for the spanish language #} +{{ content|set_conditional_access('language', {'langcodes': {'es':'es'}}) }} +``` + ## PHP PHP filter is disabled by default. You can enable it in `settings.php` file as follows: diff --git a/src/TwigTweakExtension.php b/src/TwigTweakExtension.php index 36e3004..dfa6917 100644 --- a/src/TwigTweakExtension.php +++ b/src/TwigTweakExtension.php @@ -6,6 +6,7 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Uuid\Uuid; +use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -118,6 +119,8 @@ class TwigTweakExtension extends AbstractExtension { new TwigFilter('entity_link', [self::class, 'entityLink']), new TwigFilter('translation', [self::class, 'entityTranslation']), new TwigFilter('cache_metadata', [self::class, 'CacheMetadata']), + // @phpcs:ignore Drupal.Arrays.Array.LongLineDeclaration + new TwigFilter('set_conditional_access', [self::class, 'setConditionalAccess']), ]; if (Settings::get('twig_tweak_enable_php_filter')) { @@ -704,6 +707,45 @@ class TwigTweakExtension extends AbstractExtension { return \Drupal::service('twig_tweak.cache_metadata_extractor')->extractCacheMetadata($input); } + /** + * Use a condition plugin to give access to a render array. + * + * The evaluation is based on the context. + * + * @param string $build + * A render array. + * @param string $plugin_id + * The plugin ID. + * @param array $configuration + * Configuration for the plugin. + * + * @return array + * The render array with the evaluation of the plugin in the #access key. + */ + public static function setConditionalAccess($build, string $plugin_id, array $configuration = []): array { + $pluginInstance = \Drupal::service('plugin.manager.condition')->createInstance($plugin_id); + $pluginInstance->setConfiguration($configuration); + $contextRepository = \Drupal::service('context.repository'); + $availableContexts = $contextRepository->getAvailableContexts(); + + // Ensure that the contexts have data by getting corresponding runtime contexts. + $availableRuntimeContexts = $contextRepository->getRuntimeContexts(array_keys($availableContexts)); + $pluginContextDefinitions = $pluginInstance->getContextDefinitions(); + foreach ($pluginContextDefinitions as $name => $pluginContextDefinition) { + // Identify and fetch the matching runtime context, with the plugin's context definition. + $matches = \Drupal::service('context.handler')->getMatchingContexts($availableRuntimeContexts, $pluginContextDefinition); + $matchingContext = reset($matches); + $build['#cache']['contexts'] = Cache::mergeContexts($matchingContext->getCacheContexts(), $build['#cache']['contexts'] ?? []); + $build['#cache']['tags'] = Cache::mergeTags($matchingContext->getCacheTags(), $build['#cache']['tags'] ?? []); + $build['#cache']['max-age'] = Cache::mergeMaxAges($matchingContext->getCacheMaxAge(), $build['#cache']['max-age'] ?? Cache::PERMANENT); + + // Set the value to the plugin's context, from runtime context value. + $pluginInstance->setContextValue($name, $matchingContext->getContextValue()); + } + $build['#access'] = $pluginInstance->evaluate(); + return $build; + } + /** * Evaluates a string of PHP code. *