In Drupal we can define theme settings that can for instance allow us to create "theme variations".
For instance allow a user to choose a color-scheme, or even define individual colors, sizes, ...
But what if you want to be able to, when creating content, decide what variation is used on that content-page/entity/field?
One way would be to implement a pseudo-field that adds one or more select-box's to all entity forms. That would then populate it's information by reading the theme's info file.
In Drupal 7, I would do something like:
/**
* @param bool $rebuild
* @return array<
* $entityType:Array<
* $bundle:Array<Options>
* >
* >
*/
function _ema_entity_variation_info($rebuild=true) {
$cid = 'ema_entity_variation_info';
if (!$rebuild) {
$variations = &drupal_static(__FUNCTION__);
if (isset($variations)) {
return $variations;
}
if ($cache = cache_get($cid)) {
$variations = $cache->data;
return $variations;
}
}
$variations = array();
$themes = list_themes();
foreach ($themes as $theme_key => $theme) {
if ($theme->status && isset($theme->info['variations'])) {
$variations += $theme->info['variations'];
}
}
cache_set($cid, $variations);
return $variations;
}
/**
* Implements hook_entity_property_info_alter().
*/
function ema_entity_variation_entity_property_info_alter(&$info) {
$variations = _ema_entity_variation_info();
foreach ($variations as $entity_type => $variation_info) {
if (!isset($info[$entity_type])) { continue; }
foreach ($variation_info as $bundle => $bundle_variations) {
if (!isset($info[$entity_type]['bundles'][$bundle])) { continue; }
$properties = &$info[$entity_type]['bundles'][$bundle]['properties'];
foreach($bundle_variations as $variation_name => $variation_options) {
$properties['variation_'.$variation_name] = array(
'type' => 'token',
'label' => t('Variation'),
'description' => t('Provides variations'),
'setter callback' => 'entity_property_verbatim_set',
);
}
}
}
}
/**
* Implements hook_field_attach_form().
*/
function ema_entity_variation_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
//stupid user profiles, comments, ...
if (!isset($entity->type)) {
return;
}
$variations = ema_entity_variation_get_variations($entity_type, $entity->type);
if ($variations) {
$form['variation'] = array(
'#type' => 'fieldset',
'#title' => t('Variation'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'additional_settings'
);
foreach ($variations as $label => $options) {
$form['variation']['variation_'.$label] = array(
'#type' => 'select',
'#title' => $label,
'#options' => $options,
'#default_value' => isset($entity->variations[$label]) ? $entity->variations[$label] : NULL
);
}
}
}
(yes I know It's not perfect and only works with a single theme, but it got the job done).
This would allow a drupal themer (not everyone is full-stack) to easily define "variations" for all entity types/bundles in his info file:
variations[node][basic_page][content_align][left] = Left
variations[node][basic_page][content_align][center] = Center
And then in his theme add a class:
/**
* Implements hook_preprocess_entity
*/
function THEME_preprocess_node(&$vars) {
if (isset($vars['elements']['#entity']) && isset($vars['elements']['#entity']->variations)) {
foreach ($vars['elements']['#entity']->variations as $variation_name => $value) {
$vars['classes_array'][] = drupal_html_class($variation_name).'--'.drupal_html_class($value);
}
}
}
This however feels oh so wrong and I'm now looking into how this could be done "the drupal 8 way".
- I looked into plugins, but themes can't implement plugins (?), atleast my plugin manager is not finding them.
- I looked into reading the info file (using theme handled and such), but this just feels wrong (or is my gut feeling off here?)
- I can only move all the form logic into the theme if it is also used for the admin, this is however hardly ever the case. And I want to support multiple themes and being able to select the variations on a per theme basis.
Anyone has any idea's where I should look into?