sites_group_overrides-1.x-dev/sites_group_overrides.module
sites_group_overrides.module
<?php
/**
* @file
* sites_group_overrides module.
*/
use Drupal\Core\Url;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\sites_group_overrides\Entity\GroupRelationship;
use Drupal\sites_group_overrides\Plugin\DataType\EntityAdapter;
use Drupal\group\Entity\Storage\GroupRelationshipStorageInterface;
use Drupal\sites_group_overrides\Entity\LayoutBuilderEntityViewDisplay;
use Drupal\sites_group_overrides\SitesGroupOverridesInlineBlockEntityOperations;
/**
* Implements hook_entity_type_alter().
*/
function sites_group_overrides_entity_type_alter(array &$entity_types) {
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
$entity_types['entity_view_display']->setClass(LayoutBuilderEntityViewDisplay::class);
}
/**
* Implements hook_data_type_info_alter().
*/
function sites_group_overrides_data_type_info_alter(&$data_types) {
foreach ($data_types as &$data_type) {
if ($data_type['class'] == \Drupal\Core\Entity\Plugin\DataType\EntityAdapter::class) {
$data_type['class'] = EntityAdapter::class;
}
}
}
/**
* Implements hook_entity_translation_delete().
*/
function sites_group_overrides_entity_translation_delete(EntityInterface $translation) {
// Delete the corresponding group relationship translations when they exist.
if (!$translation instanceof GroupRelationshipInterface) {
$storage = \Drupal::entityTypeManager()->getStorage('group_relationship');
assert($storage instanceof GroupRelationshipStorageInterface);
if ($group_relationships = $storage->loadByEntity($translation)) {
foreach ($group_relationships as $group_relationship) {
$langcode = $translation->language()->getId();
if ($group_relationship->hasTranslation($langcode)) {
$group_relationship->removeTranslation($langcode);
$group_relationship->save();
}
}
}
}
}
/**
* Implements hook_entity_translation_insert().
*/
function sites_group_overrides_entity_translation_insert(EntityInterface $translation) {
/** @var \Drupal\sites_group\SitesGroupServiceInterface $sites_group_service */
$sites_group_service = \Drupal::service('sites_group.service');
/** @var \Drupal\sites_language\SitesLanguageServiceInterface $sites_language */
$sites_language = \Drupal::service('sites_language.service');
// Add the new translation from the parent entity to the group relationship.
if (!$translation instanceof GroupRelationshipInterface) {
$storage = \Drupal::entityTypeManager()->getStorage('group_relationship');
assert($storage instanceof GroupRelationshipStorageInterface);
if ($group_relationships = $storage->loadByEntity($translation)) {
foreach ($group_relationships as $group_relationship) {
$langcode = $translation->language()->getId();
// Only do this if the language has been enabled on the related site.
if (!$group_relationship->hasTranslation($langcode) && $sites_language->siteHasLangcode($sites_group_service->getSiteForGroup($group_relationship->getGroup()), $langcode)) {
$group_relationship->addTranslation($langcode)->save();
}
}
}
}
}
/**
* Implements hook_ENTITY_TYPE_insert().
*/
function sites_group_overrides_group_relationship_insert(GroupRelationshipInterface $group_relationship) {
/** @var \Drupal\sites_group\SitesGroupServiceInterface $sites_group_service */
$sites_group_service = \Drupal::service('sites_group.service');
/** @var \Drupal\sites_language\SitesLanguageServiceInterface $sites_language */
$sites_language = \Drupal::service('sites_language.service');
// Add the entity translations to the group relationship entity.
if ($group_relationship->getEntity() instanceof TranslatableInterface) {
$languages = $group_relationship->getEntity()->getTranslationLanguages();
foreach ($languages as $language) {
if (!$group_relationship->hasTranslation($language->getId()) && $group_relationship->getEntity()->hasTranslation($language->getId())) {
$langcode = $language->getId();
// Only do this if the language has been enabled on the related site.
if ($sites_language->siteHasLangcode($sites_group_service->getSiteForGroup($group_relationship->getGroup()), $langcode)) {
$group_relationship->addTranslation($langcode)->save();
}
}
}
}
}
/**
* Implements hook_entity_base_field_info_alter().
*/
function sites_group_overrides_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
// Make relationship label translatable.
if ($entity_type->id() == 'group_relationship' && $fields['label'] instanceof BaseFieldDefinition) {
$fields['label']->setTranslatable(TRUE);
}
}
/**
* Implements hook_preprocess().
*
* Add the site id to contextual links metadata. Unfortunately the
* _contextual_links_to_id function does not provide any way to alter the placeholder
* ids. So we have to implement our own hook_preprocess to alter the metadata.
*/
function sites_group_overrides_preprocess(&$variables, $hook, $info) {
// Determine the primary theme function argument.
if (!empty($info['variables'])) {
$keys = array_keys($info['variables']);
$key = $keys[0];
}
elseif (!empty($info['render element'])) {
$key = $info['render element'];
}
if (!empty($key) && isset($variables[$key])) {
$element = $variables[$key];
}
if (isset($element) && is_array($element) && !empty($element['#contextual_links'])) {
if ($site = \Drupal::service('sites.current_site')->getSiteFromContext()) {
foreach (array_keys($element['#contextual_links']) as $contextual_link) {
$variables[$key]['#contextual_links'][$contextual_link]['metadata']['site'] = $site->getPluginId();
}
}
}
}
/**
* Implements hook_theme_registry_alter().
*
* Move sites_group_overrides_preprocess before contextual_preprocess.
*/
function sites_group_overrides_theme_registry_alter(&$theme_registry): void {
foreach ($theme_registry as &$value) {
if (empty($value['preprocess functions'])) {
continue;
}
$key_a = array_search('sites_group_overrides_preprocess', $value['preprocess functions']);
$key_b = array_search('contextual_preprocess', $value['preprocess functions']);
if ($key_a === FALSE || $key_b === FALSE) {
continue;
}
// Get positions in array.
$pos_a = array_search($key_a, array_keys($value['preprocess functions']));
$pos_b = array_search($key_b, array_keys($value['preprocess functions']));
// Move $key_a to (before) $key_b.
$out = array_splice($value['preprocess functions'], $pos_a, 1);
array_splice($value['preprocess functions'], $pos_b, 0, $out);
}
}
/**
* Implements hook_page_attachments().
*/
function sites_group_overrides_page_attachments(array &$attachments) {
// Add site id to JS settings and attach masquerade AJAX library.
if (\Drupal::currentUser()->isAnonymous()) {
return;
}
/** @var \Drupal\Core\Access\CsrfTokenGenerator $csrf_service */
$csrf_service = \Drupal::getContainer()->get('csrf_token');
$attachments['#attached']['library'][] = 'sites_group_overrides/add_site_param_to_ajax_requests';
$attachments['#attached']['drupalSettings']['sitesCsrf'] = $csrf_service->get('sites_csrf');
}
/**
* Implements hook_views_data_alter().
*/
function sites_group_overrides_views_data_alter(array &$data) {
$entity_type_manager = \Drupal::entityTypeManager();
$entity_types = $entity_type_manager->getDefinitions();
// Add language to the join for translatable entity types. This might be
// obsolete when https://www.drupal.org/project/group/issues/3311869 gets
// committed.
foreach ($data as $entity_data_table => &$data_item) {
if (isset($data_item['group_relationship']) && isset($data_item['table']['entity type'])) {
$entity_type_id = $data_item['table']['entity type'];
if ($entity_type = $entity_types[$entity_type_id]) {
$data_item['group_relationship']['relationship']['extra'][] = [
'field' => $entity_type->getKey('langcode'),
'left_field' => $entity_types['group_relationship']->getKey('langcode'),
];
}
}
}
}
/**
* Implements hook_module_implements_alter().
*
* We unset layout_builder_entity_presave() because InlineBlockEntityOperations isn't a
* service that we could decorate. We implement our own hook_presave to duplicate blocks for overrides.
*/
function sites_group_overrides_module_implements_alter(&$implementations, $hook): void {
if ($hook == 'entity_presave') {
unset($implementations['layout_builder']);
}
}
/**
* Implements hook_entity_presave().
*
* Same as layout_builder_entity_presave but with our class.
*/
function sites_group_overrides_entity_presave(\Drupal\Core\Entity\EntityInterface $entity): void {
if (\Drupal::moduleHandler()->moduleExists('block_content')) {
/** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
$entity_operations = \Drupal::classResolver(SitesGroupOverridesInlineBlockEntityOperations::class);
$entity_operations->handlePreSave($entity);
}
}
/**
* Implements hook_entity_type_build().
*/
function sites_group_overrides_entity_type_build(&$entity_types) {
if (isset($entity_types['group_relationship'])) {
$entity_types['group_relationship']->setClass(GroupRelationship::class);
}
}
/**
* Implements reprocess_menu_local_task().
*/
function sites_group_overrides_preprocess_menu_local_task(&$variables) {
// Highlight the overrides local task.
if ($variables['link']['#url'] instanceof Url) {
$matches = [];
if (preg_match('/^entity\.(.*)\.overrides$/', $variables['link']['#url']->getRouteName(), $matches)) {
$variables['link']['#options']['attributes']['class'][] = 'button--primary';
}
}
}
/**
* Implements hook_ENTITY_TYPE_delete().
*
* Delete group_relationship_overrides section storage from the temp store.
*/
function sites_group_overrides_group_relationship_delete(GroupRelationshipInterface $relationship): void {
$name_prefix = $relationship->getPlugin()->getRelationType()->getEntityTypeId() . '.' . $relationship->getEntityId();
$name_suffix = '.sites_group:' . $relationship->getGroupId();
/** @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $storage_factory */
$storage_factory = \Drupal::service('keyvalue.expirable');
$collection = $storage_factory->get('tempstore.shared.layout_builder.section_storage.group_relationship_overrides');
foreach (array_keys($collection->getAll()) as $name) {
if (str_starts_with($name, $name_prefix) && str_ends_with($name, $name_suffix)) {
$collection->delete($name);
}
}
}
