5 * Contains bootstrap_layouts.module.
8 use Drupal\bootstrap_layouts\BootstrapLayout;
9 use Drupal\Component\Utility\Html;
10 use Drupal\Component\Utility\NestedArray;
11 use Drupal\Core\Render\Element;
12 use Drupal\Core\Template\Attribute;
13 use Drupal\layout_plugin\Layout;
16 * Implements hook_theme_registry_alter().
18 function bootstrap_layouts_theme_registry_alter(&$theme_registry) {
19 // Find all Bootstrap Layouts.
20 $layouts = Layout::layoutPluginManager()->getDefinitions();
21 $layout_theme_hooks = [];
22 foreach ($layouts as $info) {
23 if ($info['class'] === '\Drupal\bootstrap_layouts\Plugin\Layout\BootstrapLayoutsBase') {
24 $layout_theme_hooks[] = $info['theme'];
28 // Add a special internal preprocess function.
29 foreach ($theme_registry as $theme_hook => $info) {
30 if (in_array($theme_hook, $layout_theme_hooks) || (!empty($info['base hook']) && in_array($info['base hook'], $layout_theme_hooks))) {
31 $theme_registry[$theme_hook]['preprocess functions'][] = '_bootstrap_layouts_preprocess_layout';
37 * Parses an attribute string saved in the UI.
39 * @param string $string
40 * The attribute string to parse.
41 * @param array $tokens
42 * An associative array of token data to use.
45 * A parsed attributes array.
47 function _bootstrap_layouts_parse_attributes($string = NULL, array $tokens = []) {
50 /** @var \Drupal\Core\Utility\Token $token */
51 $token = \Drupal::service('token');
54 if (!empty($string)) {
55 $parts = explode(',', $string);
56 foreach ($parts as $attribute) {
57 if (strpos($attribute, '|') !== FALSE) {
58 list($key, $value) = explode('|', $token->replace($attribute, $tokens, ['clear' => TRUE]));
59 $attributes[$key] = $value;
67 * Internal preprocess callback.
69 * This is used to determine standardize variables to use in Bootstrap Layouts
70 * templates based on whatever implementation is used (i.e. Display Suite or
73 * @param array $variables
74 * Variables array, passed by reference.
76 function _bootstrap_layouts_preprocess_layout(array &$variables) {
77 // Utilize the BootstrapLayout utility class to normalize DX readability here.
78 $layout = new BootstrapLayout($variables['layout']['id'], [], $variables['settings']);
81 // Determine the entity, entity type and bundle.
82 /** @var \Drupal\Core\Entity\EntityInterface $entity */
83 $entity = isset($variables['content']['#entity']) ? $variables['content']['#entity'] : FALSE;
84 $entity_type = isset($variables['content']['#entity_type']) ? $variables['content']['#entity_type'] : FALSE;
85 $bundle = isset($variables['content']['#bundle']) ? $variables['content']['#bundle'] : FALSE;
86 $view_mode = isset($variables['content']['#view_mode']) ? $variables['content']['#view_mode'] : FALSE;
89 if ($entity_type && $entity) {
90 $tokens[$entity_type] = $entity;
92 // Copy entity to top level to improve theme experience.
93 $variables[$entity_type] = $entity;
96 // Add a layout wrapper and its attributes.
97 $variables['wrapper'] = $layout->getSetting('layout.wrapper', 'div');
98 $layout_attributes = isset($variables['attributes']) ? $variables['attributes'] : [];
99 $layout_attributes = NestedArray::mergeDeep(_bootstrap_layouts_parse_attributes($layout->getSetting('layout.attributes'), $tokens), $layout_attributes);
101 $attributes = new Attribute($layout_attributes);
102 $attributes->addClass(array_keys($layout->getSetting('layout.classes', [])));
103 if ($layout->getSetting('layout.add_layout_class')) {
104 $attributes->addClass(Html::cleanCssIdentifier($layout->getId()));
107 // Unfortunately since Display Suite doesn't abstract this bit of code, it
108 // must be duplicated in this module to support it from the UI.
109 if ($entity_type && isset($variables['content']['#ds_configuration'])) {
110 // Add theming-classes to template.
111 $entity_classes = !empty($variables['content']['#ds_configuration']['layout']['entity_classes']) ? $variables['content']['#ds_configuration']['layout']['entity_classes'] : 'old_view_mode';
112 if ($entity_classes !== 'no_classes') {
113 if ($entity_classes === 'all_classes') {
114 $entity_type_class = Html::cleanCssIdentifier($entity_type);
115 $entity_classes = [$entity_type_class];
117 $entity_classes[] = "$entity_type_class--type-" . Html::cleanCssIdentifier($bundle);
120 $entity_classes[] = "$entity_type_class--view-mode-" . Html::cleanCssIdentifier($view_mode);
122 $attributes->addClass($entity_classes);
124 // Add (old style, non cleaned) view-mode-{name} to classes.
125 elseif ($entity_classes === 'old_view_mode' && $view_mode && !$attributes->hasClass("view-mode-$view_mode")) {
126 $attributes->addClass("view-mode-$view_mode");
130 // Let other modules know we have rendered.
131 $variables['rendered_by_ds'] = TRUE;
133 // Let other modules alter the ds array before rendering.
136 'entity_type' => $entity_type,
138 'view_mode' => $view_mode,
140 \Drupal::moduleHandler()->alter('ds_pre_render', $variables['content'], $context, $variables);
143 // Set the attributes variable.
144 $variables['attributes'] = $attributes;
146 // Create region variables based on the layout settings.
147 foreach ($layout->getSetting('regions') as $region => $region_settings) {
148 $region_attributes = new Attribute(_bootstrap_layouts_parse_attributes($region_settings['attributes'], $tokens));
149 $region_attributes->addClass(array_keys($region_settings['classes']));
150 if (!empty($region_settings['add_region_classes'])) {
151 $region_attributes->addClass(['bs-region', Html::cleanCssIdentifier("bs-region--$region")]);
153 unset($region_settings['classes']);
154 $region_settings['attributes'] = $region_attributes;
155 $region_settings['content'] = isset($variables['content'][$region]) && !Element::isEmpty($variables['content'][$region]) ? $variables['content'][$region] : NULL;
156 $variables[$region] = $region_settings;