From bafcce49854202f5450cc4e329810a324c0e0da7 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Wed, 6 Mar 2024 09:03:36 +0200 Subject: [PATCH 01/10] UHF-9712: Add OGImageManager --- documentation/tokens.md | 51 +++++++++ fixtures/og-global-sv.png | Bin 0 -> 15649 bytes fixtures/og-global.png | Bin 0 -> 12898 bytes helfi_platform_config.module | 41 -------- helfi_platform_config.services.yml | 13 +++ helfi_platform_config.tokens.inc | 66 ++++++++++++ .../hdbt_admin_tools.tokens.inc | 77 +------------- .../helfi_platform_config_base.services.yml | 7 ++ .../src/Token/NodeImageBuilder.php | 99 ++++++++++++++++++ .../helfi_tpr_config.info.yml | 1 + .../helfi_tpr_config/helfi_tpr_config.module | 4 + .../helfi_tpr_config.services.yml | 7 ++ modules/helfi_tpr_config/src/Entity/Unit.php | 59 +++++++++++ .../src/Token/UnitImageBuilder.php | 46 ++++++++ phpstan.neon | 14 +-- src/Token/DefaultImageBuilder.php | 64 +++++++++++ src/Token/OGImageBuilderInterface.php | 34 ++++++ src/Token/OGImageManager.php | 85 +++++++++++++++ 18 files changed, 545 insertions(+), 123 deletions(-) create mode 100644 documentation/tokens.md create mode 100644 fixtures/og-global-sv.png create mode 100644 fixtures/og-global.png create mode 100644 helfi_platform_config.tokens.inc create mode 100644 modules/helfi_platform_config_base/helfi_platform_config_base.services.yml create mode 100644 modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php create mode 100644 modules/helfi_tpr_config/helfi_tpr_config.services.yml create mode 100644 modules/helfi_tpr_config/src/Entity/Unit.php create mode 100644 modules/helfi_tpr_config/src/Token/UnitImageBuilder.php create mode 100644 src/Token/DefaultImageBuilder.php create mode 100644 src/Token/OGImageBuilderInterface.php create mode 100644 src/Token/OGImageManager.php diff --git a/documentation/tokens.md b/documentation/tokens.md new file mode 100644 index 000000000..ff6e5d59c --- /dev/null +++ b/documentation/tokens.md @@ -0,0 +1,51 @@ +# Tokens + +Helfi platform config implements `hook_tokens()`, and with the help of `helfi_platform_config.og_image_manager`, the `[*:shareable-image]` token is provided. Modules may implement services that handle this token for their entity types. + +Modules should still implement `hook_tokens_info` to provide information about the implemented token. + +## Defining image builder service + +Add a new service: + +```yml +# yourmodule/yourmodule.services.yml + yourmodule.og_image.your_entity_type: + class: Drupal\yourmodule\Token\YourEntityImageBuilder + arguments: [] + tags: + - { name: helfi_platform_config.og_image_builder, priority: 100 } +``` + +```php +# yourmodule/src/Token/YourEntityImageBuilder.php +field_image->entity->toUrl(); + } + +} +``` diff --git a/fixtures/og-global-sv.png b/fixtures/og-global-sv.png new file mode 100644 index 0000000000000000000000000000000000000000..a20c54342f516c28665e7977caf919aaeb1871cd GIT binary patch literal 15649 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 t('Page title suffix'), - 'description' => t('Official suffix for page title.'), - ]; - return $info; -} - /** * Grants permissions for given role. * @@ -337,35 +325,6 @@ function helfi_platform_config_remove_permissions_from_all_roles(array $permissi } } -/** - * Implements hook_tokens(). - */ -function helfi_platform_config_tokens( - $type, - $tokens, - array $data, - array $options, - BubbleableMetadata $bubbleable_metadata -): array { - $replacements = []; - - foreach ($tokens as $name => $original) { - if ($name === 'page-title-suffix') { - $language = Drupal::languageManager() - ->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE); - - $replacements[$original] = match ($language->getId()) { - 'fi' => 'Helsingin kaupunki', - 'sv' => 'Helsingfors stad', - 'ru' => 'Гopoд Xeльcинки', - default => 'City of Helsinki', - }; - } - } - - return $replacements; -} - /** * Implements hook_system_breadcrumb_alter(). */ diff --git a/helfi_platform_config.services.yml b/helfi_platform_config.services.yml index c1220b744..d26ed6a4e 100644 --- a/helfi_platform_config.services.yml +++ b/helfi_platform_config.services.yml @@ -60,3 +60,16 @@ services: arguments: - 'helfi_platform_config' + helfi_platform_config.og_image_manager: + class: Drupal\helfi_platform_config\Token\OGImageManager + tags: + - { name: service_collector, call: add, tag: helfi_platform_config.og_image_builder } + + helfi_platform_config.og_image.default: + class: Drupal\helfi_platform_config\Token\DefaultImageBuilder + arguments: + - '@module_handler' + - '@language_manager' + - '@file_url_generator' + tags: + - { name: helfi_platform_config.og_image_builder, priority: 100 } diff --git a/helfi_platform_config.tokens.inc b/helfi_platform_config.tokens.inc new file mode 100644 index 000000000..0f40ea809 --- /dev/null +++ b/helfi_platform_config.tokens.inc @@ -0,0 +1,66 @@ + t('Page title suffix'), + 'description' => t('Official suffix for page title.'), + ]; + return $info; +} + +/** + * Implements hook_tokens(). + * + * @see \Drupal\helfi_platform_config\Token\OGImageManager + */ +function helfi_platform_config_tokens( + $type, + $tokens, + array $data, + array $options, + BubbleableMetadata $bubbleable_metadata +) : array { + $replacements = []; + + foreach ($tokens as $name => $original) { + if ($name === 'shareable-image' && isset($data[$type])) { + $entity = $data[$type]; + + if ($entity instanceof EntityInterface) { + /** @var \Drupal\helfi_platform_config\Token\OGImageManager $image_manager */ + $image_manager = \Drupal::service('helfi_platform_config.og_image_manager'); + + $replacements[$original] = $image_manager->buildUrl($entity); + } + } + + if ($name === 'page-title-suffix') { + $language = Drupal::languageManager() + ->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE); + + $replacements[$original] = match ($language->getId()) { + 'fi' => 'Helsingin kaupunki', + 'sv' => 'Helsingfors stad', + 'ru' => 'Гopoд Xeльcинки', + default => 'City of Helsinki', + }; + } + } + + return $replacements; +} diff --git a/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc b/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc index 1b7417a59..55fdaeba7 100644 --- a/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc +++ b/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc @@ -5,10 +5,7 @@ * Contains token data for helfi admin tools. */ -use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Render\BubbleableMetadata; -use Drupal\image\Entity\ImageStyle; -use Drupal\media\MediaInterface; use Drupal\paragraphs\ParagraphInterface; /** @@ -49,80 +46,10 @@ function hdbt_admin_tools_tokens( $replacements = []; foreach ($tokens as $name => $original) { - $default_image = ''; - - /** @var Drupal\Core\Extension\ThemeHandler $theme_handler */ - $theme_handler = Drupal::service('theme_handler'); - - // Add default og-image as the shareable image. - if ($theme_handler->themeExists('hdbt')) { - $theme = $theme_handler->getTheme('hdbt'); - $current_language = \Drupal::languageManager() - ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); - $image_file_name = $current_language === 'sv' ? 'og-global-sv.png' : 'og-global.png'; - - /** @var \Drupal\Core\File\FileUrlGeneratorInterface $service */ - $service = \Drupal::service('file_url_generator'); - $default_image = $service->generate("{$theme->getPath()}/src/images/{$image_file_name}") - ->toString(TRUE) - ->getGeneratedUrl(); - } - // Custom token for default-og-image. if ($name === 'default-og-image') { - $replacements[$original] = $default_image; - } - - // Handle fallback image for TPR Unit. - if ($name === 'picture' && $type === 'tpr_unit' && !empty($data[$type])) { - /** @var \Drupal\helfi_tpr\Entity\Unit $entity */ - $entity = $data[$type]; - $replacements[$original] = $entity->getPictureUrl() ?? $default_image; - } - - // Custom token for shareable-image. - if ($name === 'shareable-image' && !empty($data['node'])) { - /** @var \Drupal\node\NodeInterface $node */ - $node = $data['node']; - $image_url = $default_image; - - $image_style = ImageStyle::load('og_image'); - - if ( - $node->hasField('field_liftup_image') && - isset($node->field_liftup_image->entity) && - $node->field_liftup_image->entity instanceof MediaInterface && - $node->field_liftup_image->entity->hasField('field_media_image') - ) { - // If liftup image has an image set, use it as the shareable image. - $image_entity = $node->field_liftup_image->entity->field_media_image; - $image_path = $image_entity->entity->getFileUri(); - $image_url = $image_style->buildUrl($image_path); - } - elseif ( - $node->hasField('field_image') && - isset($node->field_image->entity) && - $node->field_image->entity instanceof MediaInterface && - $node->field_image->entity->hasField('field_media_image') - ) { - // If the node has an image, use that. - $image_entity = $node->field_image->entity->field_media_image; - $image_path = $image_entity->entity->getFileUri(); - $image_url = $image_style->buildUrl($image_path); - } - elseif ( - $node->hasField('field_organization') && - $node->get('field_organization')?->entity?->hasField('field_default_image') && - !$node->get('field_organization')->entity->get('field_default_image')->isEmpty() - ) { - // Use the image from the taxonomy term. - $taxonomy_term = $node->field_organization->entity; - $image_entity = $taxonomy_term->field_default_image; - $image_path = $image_entity->entity->getFileUri(); - $image_url = $image_style->buildUrl($image_path); - } - - $replacements[$original] = $image_url; + $replacements[$original] = \Drupal::service('helfi_platform_config.og_image.default') + ->getDefaultShareableImageUrl(); } // Custom token for lead in. diff --git a/modules/helfi_platform_config_base/helfi_platform_config_base.services.yml b/modules/helfi_platform_config_base/helfi_platform_config_base.services.yml new file mode 100644 index 000000000..b56afd7cc --- /dev/null +++ b/modules/helfi_platform_config_base/helfi_platform_config_base.services.yml @@ -0,0 +1,7 @@ +services: + helfi_platform_config_base.og_image.node: + class: Drupal\helfi_platform_config_base\Token\NodeImageBuilder + arguments: + - '@entity_type.manager' + tags: + - { name: helfi_platform_config.og_image_builder } diff --git a/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php b/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php new file mode 100644 index 000000000..8dc8d6d90 --- /dev/null +++ b/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php @@ -0,0 +1,99 @@ +getImage($entity)) { + /** @var \Drupal\image\ImageStyleInterface $image_style */ + $image_style = $this->entityTypeManager + ->getStorage('image_style') + ->load('og_image'); + + return $image_style->buildUrl($image_file->getFileUri()); + } + + return NULL; + } + + /** + * Get shareable image from node entity. + * + * @param \Drupal\node\NodeInterface $node + * Node. + * + * @return \Drupal\file\FileInterface|null + * Image entity. + */ + private function getImage(NodeInterface $node) : ?FileInterface { + if ( + $node->hasField('field_liftup_image') && + isset($node->field_liftup_image->entity) && + $node->field_liftup_image->entity instanceof MediaInterface && + $node->field_liftup_image->entity->hasField('field_media_image') + ) { + // If liftup image has an image set, use it as the shareable image. + $file = $node->field_liftup_image->entity->field_media_image->entity; + assert($file instanceof FileInterface); + return $file; + } + elseif ( + $node->hasField('field_image') && + isset($node->field_image->entity) && + $node->field_image->entity instanceof MediaInterface && + $node->field_image->entity->hasField('field_media_image') + ) { + // If the node has an image, use that. + $file = $node->field_image->entity->field_media_image->entity; + assert($file instanceof FileInterface); + return $file; + } + elseif ( + $node->hasField('field_organization') && + $node->get('field_organization')?->entity?->hasField('field_default_image') && + !$node->get('field_organization')->entity->get('field_default_image')->isEmpty() + ) { + // Use the image from the taxonomy term. + $taxonomy_term = $node->field_organization->entity; + $file = $taxonomy_term->field_default_image->entity; + assert($file instanceof FileInterface); + return $file; + } + + return NULL; + } + +} diff --git a/modules/helfi_tpr_config/helfi_tpr_config.info.yml b/modules/helfi_tpr_config/helfi_tpr_config.info.yml index f0399ea16..53490d271 100644 --- a/modules/helfi_tpr_config/helfi_tpr_config.info.yml +++ b/modules/helfi_tpr_config/helfi_tpr_config.info.yml @@ -9,6 +9,7 @@ dependencies: - 'helfi_base_content:helfi_base_content' - 'helfi_media:helfi_media' - 'helfi_paragraphs_content_liftup:helfi_paragraphs_content_liftup' + - 'helfi_image_styles:helfi_image_styles' - 'helfi_tpr:helfi_tpr' - 'imagecache_external:imagecache_external' - 'views:views' diff --git a/modules/helfi_tpr_config/helfi_tpr_config.module b/modules/helfi_tpr_config/helfi_tpr_config.module index 20176b2b2..20e6c7d97 100644 --- a/modules/helfi_tpr_config/helfi_tpr_config.module +++ b/modules/helfi_tpr_config/helfi_tpr_config.module @@ -15,6 +15,7 @@ use Drupal\Core\Url; use Drupal\helfi_platform_config\DTO\ParagraphTypeCollection; use Drupal\helfi_tpr_config\Entity\ServiceList; use Drupal\helfi_tpr_config\Entity\ServiceListSearch; +use Drupal\helfi_tpr_config\Entity\Unit; use Drupal\helfi_tpr_config\Entity\UnitSearch; use Drupal\linkit\Entity\Profile; use Drupal\paragraphs\Entity\Paragraph; @@ -23,6 +24,9 @@ use Drupal\paragraphs\Entity\Paragraph; * Implements hook_entity_bundle_info_alter(). */ function helfi_tpr_config_entity_bundle_info_alter(array &$bundles): void { + if (isset($bundles['tpr_unit']['tpr_unit'])) { + $bundles['tpr_unit']['tpr_unit']['class'] = Unit::class; + } if (isset($bundles['paragraph']['service_list'])) { $bundles['paragraph']['service_list']['class'] = ServiceList::class; } diff --git a/modules/helfi_tpr_config/helfi_tpr_config.services.yml b/modules/helfi_tpr_config/helfi_tpr_config.services.yml new file mode 100644 index 000000000..d60d10f6b --- /dev/null +++ b/modules/helfi_tpr_config/helfi_tpr_config.services.yml @@ -0,0 +1,7 @@ +services: + helfi_tpr_config.og_image.tpr_entity: + class: Drupal\helfi_tpr_config\Token\UnitImageBuilder + arguments: + - '@entity_type.manager' + tags: + - { name: helfi_platform_config.og_image_builder } diff --git a/modules/helfi_tpr_config/src/Entity/Unit.php b/modules/helfi_tpr_config/src/Entity/Unit.php new file mode 100644 index 000000000..9c465e10a --- /dev/null +++ b/modules/helfi_tpr_config/src/Entity/Unit.php @@ -0,0 +1,59 @@ +get('picture_url_override')->entity; + + if (!$picture_url) { + $url = $this->get('picture_url')->value; + + // Run image url through imagecache_external so that we + // can apply image style. + if ($imageStyle) { + $image_path = imagecache_external_generate_path($url); + + if ($image_path) { + return $imageStyle->buildUrl($image_path); + } + + return NULL; + } + + return $url; + } + + if ($file = $picture_url->get('field_media_image')->entity) { + /** @var \Drupal\file\FileInterface $file */ + if ($imageStyle) { + return $imageStyle->buildUrl($file->getFileUri()); + } + + try { + return $file->createFileUrl(FALSE) ?: NULL; + } + catch (\Exception) { + } + } + return NULL; + } + +} diff --git a/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php b/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php new file mode 100644 index 000000000..514deb937 --- /dev/null +++ b/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php @@ -0,0 +1,46 @@ +entityTypeManager + ->getStorage('image_style') + ->load('og_image'); + + return $entity->getPictureUrlWithImageStyle($image_style); + } + +} diff --git a/phpstan.neon b/phpstan.neon index 7b326a702..53478910c 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -52,30 +52,30 @@ parameters: path: modules/hdbt_admin_tools/src/Controller/ListController.php - message: '#^Access to an undefined property Drupal\\media\\MediaInterface::\$field_media_image.#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php reportUnmatched: false - message: '#^Access to an undefined property Drupal\\node\\NodeInterface::\$field_organization.#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php reportUnmatched: false - message: '#^Access to an undefined property Drupal\\Core\\Entity\\EntityInterface::\$field_default_image.#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php reportUnmatched: false - message: '#^Call to an undefined method Drupal\\Core\\Entity\\EntityInterface::getFileUri\(\).#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php reportUnmatched: false - message: '#^Call to an undefined method Drupal\\Core\\Entity\\EntityInterface::getFileUri\(\).#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php reportUnmatched: false - message: '#^Call to an undefined method Drupal\\Core\\Entity\\EntityInterface::hasField\(\).#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php - message: '#^Call to an undefined method Drupal\\Core\\Entity\\EntityInterface::get\(\).#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php - message: '#^Call to an undefined method Drupal\\Core\\TypedData\\TypedDataInterface::getTarget\(\).#' path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc diff --git a/src/Token/DefaultImageBuilder.php b/src/Token/DefaultImageBuilder.php new file mode 100644 index 000000000..562787f64 --- /dev/null +++ b/src/Token/DefaultImageBuilder.php @@ -0,0 +1,64 @@ +getDefaultShareableImageUrl(); + } + + /** + * Get default og image url. + * + * This image is used as a thumbnail in social networks and other services. + * + * @returns string|null + * Url to default og image URL. + */ + public function getDefaultShareableImageUrl() : string { + $module = $this->moduleHandler->getModule('helfi_platform_config'); + $current_language = $this->languageManager + ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); + + $image_file_name = $current_language === 'sv' ? 'og-global-sv.png' : 'og-global.png'; + + return $this->fileUrlGenerator + ->generate("{$module->getPath()}/fixtures/{$image_file_name}") + ->setAbsolute(TRUE) + ->toString(TRUE) + ->getGeneratedUrl(); + } + +} diff --git a/src/Token/OGImageBuilderInterface.php b/src/Token/OGImageBuilderInterface.php new file mode 100644 index 000000000..515ac8530 --- /dev/null +++ b/src/Token/OGImageBuilderInterface.php @@ -0,0 +1,34 @@ +builders[$priority][] = $builder; + $this->sortedBuilders = []; + } + + /** + * Builds image url for given entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * + * @return string|null + * OG image url or NULL on failure. + */ + public function buildUrl(EntityInterface $entity) : ?string { + $image_url = NULL; + + foreach ($this->getBuilders() as $builder) { + if ($builder->applies($entity)) { + if ($url = $builder->buildUrl($entity)) { + // Replace the value only if buildUrl return non-NULL values. + // This allows previous image builders to provide default images + // in case field value is missing etc. + $image_url = $url; + } + } + } + + return $image_url; + } + + /** + * Gets sorted list of image builders. + * + * @return \Drupal\helfi_platform_config\Token\OGImageBuilderInterface[] + * Image builders sorted according to priority. + */ + private function getBuilders() : array { + if (empty($this->sortedBuilders)) { + krsort($this->builders); + $this->sortedBuilders = array_merge(...$this->builders); + } + + return $this->sortedBuilders; + } + +} From e0ae4a8ed8ca29f39751282fca1b699cac03284a Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Tue, 12 Mar 2024 10:47:45 +0200 Subject: [PATCH 02/10] UHF-9712: Move hdbt_admin_tools.tokens.inc to helfi_platform_config --- helfi_platform_config.tokens.inc | 63 +++++++++++- .../hdbt_admin_tools.tokens.inc | 98 ------------------- phpstan.neon | 2 +- 3 files changed, 62 insertions(+), 101 deletions(-) delete mode 100644 modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc diff --git a/helfi_platform_config.tokens.inc b/helfi_platform_config.tokens.inc index 0f40ea809..7d8844a6c 100644 --- a/helfi_platform_config.tokens.inc +++ b/helfi_platform_config.tokens.inc @@ -16,10 +16,25 @@ use Drupal\paragraphs\ParagraphInterface; * Implements hook_token_info(). */ function helfi_platform_config_token_info() : array { + $info['tokens']['site']['default-og-image'] = [ + 'name' => t('Default OG Image'), + 'description' => t('Default OG image is used as a default thumbnail in social networks and other services.'), + ]; $info['tokens']['site']['page-title-suffix'] = [ 'name' => t('Page title suffix'), 'description' => t('Official suffix for page title.'), ]; + $info['tokens']['node']['shareable-image'] = [ + 'name' => t('Shareable image'), + 'description' => t('Shareable image is used as a thumbnail in social networks and other services.'), + ]; + + $info['tokens']['node']['lead-in'] = [ + 'name' => t('Lead in'), + 'description' => t( + 'Lead in will try to use the hero paragraph description if it exists. If not, it will use the node lead in field.' + ), + ]; return $info; } @@ -48,8 +63,12 @@ function helfi_platform_config_tokens( $replacements[$original] = $image_manager->buildUrl($entity); } } - - if ($name === 'page-title-suffix') { + // Custom token for default-og-image. + elseif ($name === 'default-og-image') { + $replacements[$original] = \Drupal::service('helfi_platform_config.og_image.default') + ->getDefaultShareableImageUrl(); + } + elseif ($name === 'page-title-suffix') { $language = Drupal::languageManager() ->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE); @@ -60,6 +79,46 @@ function helfi_platform_config_tokens( default => 'City of Helsinki', }; } + // Custom token for lead in. + elseif ($name === 'lead-in' && !empty($data['node'])) { + /** @var \Drupal\node\NodeInterface $node */ + $node = $data['node']; + $lead_in_text = ''; + + // Check if lead in field exists. + if ( + $node->hasField('field_lead_in') && + !$node?->get('field_lead_in')?->isEmpty() + ) { + // Use lead in field as lead in text. + $lead_in_text = $node->get('field_lead_in')->value; + } + + // Check if hero paragraph and hero paragraph description exists. + if ( + $node->hasField('field_hero') && + !$node->get('field_hero')?->first()?->isEmpty() + ) { + // Get hero paragraph. + $hero = $node->get('field_hero') + ?->first() + ?->get('entity') + ?->getTarget() + ?->getValue(); + + if ( + $hero instanceof ParagraphInterface && + $hero->hasField('field_hero_desc') && + !$hero->get('field_hero_desc')->isEmpty() + ) { + // Use hero paragraph description as lead in text. + $lead_in_text = $hero->get('field_hero_desc')->value; + } + } + + // Add lead in text to replacements. + $replacements[$original] = $lead_in_text; + } } return $replacements; diff --git a/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc b/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc deleted file mode 100644 index 55fdaeba7..000000000 --- a/modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc +++ /dev/null @@ -1,98 +0,0 @@ - t('Default OG Image'), - 'description' => t('Default OG image is used as a default thumbnail in social networks and other services.'), - ]; - - $info['tokens']['node']['shareable-image'] = [ - 'name' => t('Shareable image'), - 'description' => t('Shareable image is used as a thumbnail in social networks and other services.'), - ]; - - $info['tokens']['node']['lead-in'] = [ - 'name' => t('Lead in'), - 'description' => t( - 'Lead in will try to use the hero paragraph description if it exists. If not, it will use the node lead in field.' - ), - ]; - - return $info; -} - -/** - * Implements hook_tokens(). - */ -function hdbt_admin_tools_tokens( - $type, - $tokens, - array $data, - array $options, - BubbleableMetadata $bubbleable_metadata -) { - $replacements = []; - - foreach ($tokens as $name => $original) { - // Custom token for default-og-image. - if ($name === 'default-og-image') { - $replacements[$original] = \Drupal::service('helfi_platform_config.og_image.default') - ->getDefaultShareableImageUrl(); - } - - // Custom token for lead in. - if ($name === 'lead-in' && !empty($data['node'])) { - /** @var \Drupal\node\NodeInterface $node */ - $node = $data['node']; - $lead_in_text = ''; - - // Check if lead in field exists. - if ( - $node->hasField('field_lead_in') && - !$node?->get('field_lead_in')?->isEmpty() - ) { - // Use lead in field as lead in text. - $lead_in_text = $node->get('field_lead_in')->value; - } - - // Check if hero paragraph and hero paragraph description exists. - if ( - $node->hasField('field_hero') && - !$node->get('field_hero')?->first()?->isEmpty() - ) { - // Get hero paragraph. - $hero = $node->get('field_hero') - ?->first() - ?->get('entity') - ?->getTarget() - ?->getValue(); - - if ( - $hero instanceof ParagraphInterface && - $hero->hasField('field_hero_desc') && - !$hero->get('field_hero_desc')->isEmpty() - ) { - // Use hero paragraph description as lead in text. - $lead_in_text = $hero->get('field_hero_desc')->value; - } - } - - // Add lead in text to replacements. - $replacements[$original] = $lead_in_text; - } - } - - return $replacements; -} diff --git a/phpstan.neon b/phpstan.neon index 53478910c..ed41ffc90 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -78,7 +78,7 @@ parameters: path: modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php - message: '#^Call to an undefined method Drupal\\Core\\TypedData\\TypedDataInterface::getTarget\(\).#' - path: modules/hdbt_admin_tools/hdbt_admin_tools.tokens.inc + path: helfi_platform_config.tokens.inc - message: '#^Call to an undefined method Drupal\\Core\\Field\\FieldDefinitionInterface::save\(\).#' path: helfi_platform_config.module From e9893da84669a2913ec82245175c0b5af505a7bd Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 11 Mar 2024 11:00:14 +0200 Subject: [PATCH 03/10] UHF-9530: Unify tpr tokens with rest of helfi_platform_config --- .../config/install/metatag.metatag_defaults.tpr_unit.yml | 2 +- modules/helfi_tpr_config/helfi_tpr_config.install | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/helfi_tpr_config/config/install/metatag.metatag_defaults.tpr_unit.yml b/modules/helfi_tpr_config/config/install/metatag.metatag_defaults.tpr_unit.yml index cfbc08b0d..e1ba9e20d 100644 --- a/modules/helfi_tpr_config/config/install/metatag.metatag_defaults.tpr_unit.yml +++ b/modules/helfi_tpr_config/config/install/metatag.metatag_defaults.tpr_unit.yml @@ -12,7 +12,7 @@ tags: article_published_time: '[tpr_unit:created:html_datetime]' og_description: '[tpr_unit:description:summary]' og_email: '[tpr_unit:email]' - og_image: '[tpr_unit:picture]' + og_image: '[tpr_unit:shareable-image]' og_latitude: '[tpr_unit:latitude]' og_longitude: '[tpr_unit:longitude]' og_phone_number: '[tpr_unit:phone]' diff --git a/modules/helfi_tpr_config/helfi_tpr_config.install b/modules/helfi_tpr_config/helfi_tpr_config.install index 4716268ad..d67cd1d0a 100644 --- a/modules/helfi_tpr_config/helfi_tpr_config.install +++ b/modules/helfi_tpr_config/helfi_tpr_config.install @@ -397,3 +397,12 @@ function helfi_tpr_config_update_9057(): void { \Drupal::service('helfi_platform_config.config_update_helper') ->update('helfi_tpr_config'); } + +/** + * UHF-9712: Unify metatags with platform config. + */ +function helfi_tpr_config_update_9058(): void { + // Re-import 'helfi_tpr_config' configuration. + \Drupal::service('helfi_platform_config.config_update_helper') + ->update('helfi_tpr_config'); +} From cd7318aea704979aa049e1b201dc30b99d61969b Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Wed, 13 Mar 2024 15:46:12 +0200 Subject: [PATCH 04/10] UHF-9712: Move image style handling to helfi_image_styles module --- helfi_platform_config.services.yml | 3 ++ .../helfi_image_styles.module | 19 ++++++++++ .../src/Token/NodeImageBuilder.php | 18 +-------- .../helfi_tpr_config.services.yml | 2 - modules/helfi_tpr_config/src/Entity/Unit.php | 37 +++++-------------- .../src/Token/UnitImageBuilder.php | 18 +-------- src/Token/DefaultImageBuilder.php | 2 +- src/Token/OGImageBuilderInterface.php | 6 +-- src/Token/OGImageManager.php | 37 +++++++++++++++---- 9 files changed, 69 insertions(+), 73 deletions(-) diff --git a/helfi_platform_config.services.yml b/helfi_platform_config.services.yml index d26ed6a4e..e563f383c 100644 --- a/helfi_platform_config.services.yml +++ b/helfi_platform_config.services.yml @@ -62,6 +62,9 @@ services: helfi_platform_config.og_image_manager: class: Drupal\helfi_platform_config\Token\OGImageManager + arguments: + - '@module_handler' + - '@file_url_generator' tags: - { name: service_collector, call: add, tag: helfi_platform_config.og_image_builder } diff --git a/modules/helfi_image_styles/helfi_image_styles.module b/modules/helfi_image_styles/helfi_image_styles.module index d1e47fc69..0b2e27ad4 100644 --- a/modules/helfi_image_styles/helfi_image_styles.module +++ b/modules/helfi_image_styles/helfi_image_styles.module @@ -7,6 +7,8 @@ declare(strict_types=1); +use Drupal\Component\Utility\UrlHelper; + /** * Implements hook_modules_installed(). */ @@ -28,3 +30,20 @@ function helfi_image_styles_modules_installed(array $modules) : void { $moduleInstaller->install(['imagemagick']); } } + +/** + * Implements hook_og_image_uri_alter(). + * + * @see \Drupal\helfi_platform_config\Token\OGImageManager::buildUrl() + */ +function helfi_image_styles_og_image_uri_alter(&$image_uri) : void { + // Apply image style to internal uris. + if (!UrlHelper::isExternal($image_uri)) { + /** @var \Drupal\image\Entity\ImageStyle $image_style */ + $image_style = \Drupal::entityTypeManager() + ->getStorage('image_style') + ->load('og_image'); + + $image_uri = $image_style->buildUrl($image_uri); + } +} diff --git a/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php b/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php index 8dc8d6d90..3d38df73b 100644 --- a/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php +++ b/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php @@ -5,7 +5,6 @@ namespace Drupal\helfi_platform_config_base\Token; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\file\FileInterface; use Drupal\helfi_platform_config\Token\OGImageBuilderInterface; use Drupal\media\MediaInterface; @@ -16,14 +15,6 @@ */ class NodeImageBuilder implements OGImageBuilderInterface { - /** - * Constructs a new instance. - */ - public function __construct( - private readonly EntityTypeManagerInterface $entityTypeManager, - ) { - } - /** * {@inheritDoc} */ @@ -34,16 +25,11 @@ public function applies(EntityInterface $entity): bool { /** * {@inheritDoc} */ - public function buildUrl(EntityInterface $entity): ?string { + public function buildUri(EntityInterface $entity): ?string { assert($entity instanceof NodeInterface); if ($image_file = $this->getImage($entity)) { - /** @var \Drupal\image\ImageStyleInterface $image_style */ - $image_style = $this->entityTypeManager - ->getStorage('image_style') - ->load('og_image'); - - return $image_style->buildUrl($image_file->getFileUri()); + return $image_file->getFileUri(); } return NULL; diff --git a/modules/helfi_tpr_config/helfi_tpr_config.services.yml b/modules/helfi_tpr_config/helfi_tpr_config.services.yml index d60d10f6b..2c34af132 100644 --- a/modules/helfi_tpr_config/helfi_tpr_config.services.yml +++ b/modules/helfi_tpr_config/helfi_tpr_config.services.yml @@ -1,7 +1,5 @@ services: helfi_tpr_config.og_image.tpr_entity: class: Drupal\helfi_tpr_config\Token\UnitImageBuilder - arguments: - - '@entity_type.manager' tags: - { name: helfi_platform_config.og_image_builder } diff --git a/modules/helfi_tpr_config/src/Entity/Unit.php b/modules/helfi_tpr_config/src/Entity/Unit.php index 9c465e10a..35e267e0a 100644 --- a/modules/helfi_tpr_config/src/Entity/Unit.php +++ b/modules/helfi_tpr_config/src/Entity/Unit.php @@ -3,7 +3,6 @@ namespace Drupal\helfi_tpr_config\Entity; use Drupal\helfi_tpr\Entity\Unit as BaseUnit; -use Drupal\image\Entity\ImageStyle; /** * Bundle class for tpr unit. @@ -11,48 +10,30 @@ class Unit extends BaseUnit { /** - * Gets the picture url with image style. - * - * @param \Drupal\image\Entity\ImageStyle|null $imageStyle - * URL image style. Original image is returned if style is NULL. + * Gets the picture uri. * * @return string|null * The picture url. */ - public function getPictureUrlWithImageStyle(ImageStyle $imageStyle = NULL) : ? string { + public function getPictureUri() : ? string { /** @var \Drupal\media\MediaInterface $picture_url */ $picture_url = $this->get('picture_url_override')->entity; if (!$picture_url) { $url = $this->get('picture_url')->value; - // Run image url through imagecache_external so that we - // can apply image style. - if ($imageStyle) { - $image_path = imagecache_external_generate_path($url); - - if ($image_path) { - return $imageStyle->buildUrl($image_path); - } - - return NULL; - } - - return $url; + // Run url through imagecache_external so that it is possible + // to apply image styles later. This method is in a bundle class + // so that helfi_tpr does not have to add dependency to + // imagecache_external. + return $url ? imagecache_external_generate_path($url) : NULL; } if ($file = $picture_url->get('field_media_image')->entity) { /** @var \Drupal\file\FileInterface $file */ - if ($imageStyle) { - return $imageStyle->buildUrl($file->getFileUri()); - } - - try { - return $file->createFileUrl(FALSE) ?: NULL; - } - catch (\Exception) { - } + return $file->getFileUri(); } + return NULL; } diff --git a/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php b/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php index 514deb937..121752a50 100644 --- a/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php +++ b/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php @@ -5,7 +5,6 @@ namespace Drupal\helfi_tpr_config\Token; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\helfi_platform_config\Token\OGImageBuilderInterface; use Drupal\helfi_tpr_config\Entity\Unit; @@ -14,14 +13,6 @@ */ class UnitImageBuilder implements OGImageBuilderInterface { - /** - * Constructs a new instance. - */ - public function __construct( - private readonly EntityTypeManagerInterface $entityTypeManager, - ) { - } - /** * {@inheritDoc} */ @@ -32,15 +23,10 @@ public function applies(EntityInterface $entity): bool { /** * {@inheritDoc} */ - public function buildUrl(EntityInterface $entity): ?string { + public function buildUri(EntityInterface $entity): ?string { assert($entity instanceof Unit); - /** @var \Drupal\image\ImageStyleInterface $image_style */ - $image_style = $this->entityTypeManager - ->getStorage('image_style') - ->load('og_image'); - - return $entity->getPictureUrlWithImageStyle($image_style); + return $entity->getPictureUri(); } } diff --git a/src/Token/DefaultImageBuilder.php b/src/Token/DefaultImageBuilder.php index 562787f64..a10126832 100644 --- a/src/Token/DefaultImageBuilder.php +++ b/src/Token/DefaultImageBuilder.php @@ -35,7 +35,7 @@ public function applies(EntityInterface $entity): bool { /** * {@inheritDoc} */ - public function buildUrl(EntityInterface $entity): ?string { + public function buildUri(EntityInterface $entity): ?string { return $this->getDefaultShareableImageUrl(); } diff --git a/src/Token/OGImageBuilderInterface.php b/src/Token/OGImageBuilderInterface.php index 515ac8530..496c26c32 100644 --- a/src/Token/OGImageBuilderInterface.php +++ b/src/Token/OGImageBuilderInterface.php @@ -21,14 +21,14 @@ interface OGImageBuilderInterface { public function applies(EntityInterface $entity) : bool; /** - * Generate image URL. + * Generate image URI. * * @param \Drupal\Core\Entity\EntityInterface $entity * Entity to use for generation. * * @return string|null - * Image url or NULL on failure. + * Image uri or NULL on failure. */ - public function buildUrl(EntityInterface $entity) : ?string; + public function buildUri(EntityInterface $entity) : ?string; } diff --git a/src/Token/OGImageManager.php b/src/Token/OGImageManager.php index 9bd76f258..4e5d2c574 100644 --- a/src/Token/OGImageManager.php +++ b/src/Token/OGImageManager.php @@ -2,7 +2,10 @@ namespace Drupal\helfi_platform_config\Token; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\File\FileUrlGeneratorInterface; /** * Open graph image manager. @@ -28,6 +31,15 @@ final class OGImageManager { */ private array $sortedBuilders; + /** + * Constructs a new instance. + */ + public function __construct( + private readonly ModuleHandlerInterface $moduleHandler, + private readonly FileUrlGeneratorInterface $fileUrlGenerator, + ) { + } + /** * Adds image builder. * @@ -51,20 +63,31 @@ public function add(OGImageBuilderInterface $builder, int $priority = 0) : void * OG image url or NULL on failure. */ public function buildUrl(EntityInterface $entity) : ?string { - $image_url = NULL; + $image_uri = NULL; foreach ($this->getBuilders() as $builder) { if ($builder->applies($entity)) { - if ($url = $builder->buildUrl($entity)) { - // Replace the value only if buildUrl return non-NULL values. - // This allows previous image builders to provide default images - // in case field value is missing etc. - $image_url = $url; + // Replace the return value only if buildUri return non-NULL values. + // This allows previous image builders to provide default images + // in case field value is missing etc. + if ($uri = $builder->buildUri($entity)) { + $image_uri = $uri; } } } - return $image_url; + if (!$image_uri) { + return NULL; + } + + // Let modules alter the final uri (like apply image styles). + $this->moduleHandler->alter('og_image_uri', $image_uri); + + if (UrlHelper::isExternal($image_uri)) { + return $image_uri; + } + + return $this->fileUrlGenerator->generateAbsoluteString($image_uri); } /** From 3866ba53bbb6e33f13957543781810892a84bf47 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Wed, 13 Mar 2024 17:36:49 +0200 Subject: [PATCH 05/10] UHF-9712: Remove [site:default-og-image] token --- helfi_platform_config.tokens.inc | 21 +++++++------------ .../metatag.metatag_defaults.global.yml | 4 ++-- .../helfi_base_content.install | 8 +++++++ .../src/Token/NodeImageBuilder.php | 4 ++-- .../src/Token/UnitImageBuilder.php | 4 ++-- src/Token/DefaultImageBuilder.php | 21 +++---------------- src/Token/OGImageBuilderInterface.php | 8 +++---- src/Token/OGImageManager.php | 4 ++-- 8 files changed, 31 insertions(+), 43 deletions(-) diff --git a/helfi_platform_config.tokens.inc b/helfi_platform_config.tokens.inc index 7d8844a6c..72a9c0370 100644 --- a/helfi_platform_config.tokens.inc +++ b/helfi_platform_config.tokens.inc @@ -16,18 +16,18 @@ use Drupal\paragraphs\ParagraphInterface; * Implements hook_token_info(). */ function helfi_platform_config_token_info() : array { - $info['tokens']['site']['default-og-image'] = [ + $info['tokens']['site']['shareable-image'] = [ 'name' => t('Default OG Image'), 'description' => t('Default OG image is used as a default thumbnail in social networks and other services.'), ]; - $info['tokens']['site']['page-title-suffix'] = [ - 'name' => t('Page title suffix'), - 'description' => t('Official suffix for page title.'), - ]; $info['tokens']['node']['shareable-image'] = [ 'name' => t('Shareable image'), 'description' => t('Shareable image is used as a thumbnail in social networks and other services.'), ]; + $info['tokens']['site']['page-title-suffix'] = [ + 'name' => t('Page title suffix'), + 'description' => t('Official suffix for page title.'), + ]; $info['tokens']['node']['lead-in'] = [ 'name' => t('Lead in'), @@ -53,21 +53,16 @@ function helfi_platform_config_tokens( $replacements = []; foreach ($tokens as $name => $original) { - if ($name === 'shareable-image' && isset($data[$type])) { - $entity = $data[$type]; + if ($name === 'shareable-image') { + $entity = $data[$type] ?? NULL; - if ($entity instanceof EntityInterface) { + if ($entity === NULL || $entity instanceof EntityInterface) { /** @var \Drupal\helfi_platform_config\Token\OGImageManager $image_manager */ $image_manager = \Drupal::service('helfi_platform_config.og_image_manager'); $replacements[$original] = $image_manager->buildUrl($entity); } } - // Custom token for default-og-image. - elseif ($name === 'default-og-image') { - $replacements[$original] = \Drupal::service('helfi_platform_config.og_image.default') - ->getDefaultShareableImageUrl(); - } elseif ($name === 'page-title-suffix') { $language = Drupal::languageManager() ->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE); diff --git a/modules/helfi_base_content/config/rewrite/metatag.metatag_defaults.global.yml b/modules/helfi_base_content/config/rewrite/metatag.metatag_defaults.global.yml index 0a288798a..1f93ed46a 100644 --- a/modules/helfi_base_content/config/rewrite/metatag.metatag_defaults.global.yml +++ b/modules/helfi_base_content/config/rewrite/metatag.metatag_defaults.global.yml @@ -9,6 +9,6 @@ tags: twitter_cards_page_url: '[current-page:url]' twitter_cards_title: '[current-page:title] | [site:page-title-suffix]' twitter_cards_type: summary_large_image - og_image: '[site:default-og-image]' - twitter_cards_image: '[site:default-og-image]' + og_image: '[site:shareable-image]' + twitter_cards_image: '[site:shareable-image]' og_site_name: '[site:page-title-suffix]' diff --git a/modules/helfi_base_content/helfi_base_content.install b/modules/helfi_base_content/helfi_base_content.install index 8b43fc4d3..45238b1b2 100644 --- a/modules/helfi_base_content/helfi_base_content.install +++ b/modules/helfi_base_content/helfi_base_content.install @@ -311,3 +311,11 @@ function helfi_base_content_update_9007() : void { } } } + +/** + * UHF-9081 Update og_description and description meta tags. + */ +function helfi_base_content_update_9008() : void { + \Drupal::service('helfi_platform_config.config_update_helper') + ->update('helfi_base_content'); +} diff --git a/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php b/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php index 3d38df73b..f320e3ee6 100644 --- a/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php +++ b/modules/helfi_platform_config_base/src/Token/NodeImageBuilder.php @@ -18,14 +18,14 @@ class NodeImageBuilder implements OGImageBuilderInterface { /** * {@inheritDoc} */ - public function applies(EntityInterface $entity): bool { + public function applies(?EntityInterface $entity): bool { return $entity instanceof NodeInterface; } /** * {@inheritDoc} */ - public function buildUri(EntityInterface $entity): ?string { + public function buildUri(?EntityInterface $entity): ?string { assert($entity instanceof NodeInterface); if ($image_file = $this->getImage($entity)) { diff --git a/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php b/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php index 121752a50..ebfcbd6f6 100644 --- a/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php +++ b/modules/helfi_tpr_config/src/Token/UnitImageBuilder.php @@ -16,14 +16,14 @@ class UnitImageBuilder implements OGImageBuilderInterface { /** * {@inheritDoc} */ - public function applies(EntityInterface $entity): bool { + public function applies(?EntityInterface $entity): bool { return $entity instanceof Unit; } /** * {@inheritDoc} */ - public function buildUri(EntityInterface $entity): ?string { + public function buildUri(?EntityInterface $entity): ?string { assert($entity instanceof Unit); return $entity->getPictureUri(); diff --git a/src/Token/DefaultImageBuilder.php b/src/Token/DefaultImageBuilder.php index a10126832..e9517c3b9 100644 --- a/src/Token/DefaultImageBuilder.php +++ b/src/Token/DefaultImageBuilder.php @@ -28,26 +28,14 @@ public function __construct( /** * {@inheritDoc} */ - public function applies(EntityInterface $entity): bool { + public function applies(?EntityInterface $entity): bool { return TRUE; } /** * {@inheritDoc} */ - public function buildUri(EntityInterface $entity): ?string { - return $this->getDefaultShareableImageUrl(); - } - - /** - * Get default og image url. - * - * This image is used as a thumbnail in social networks and other services. - * - * @returns string|null - * Url to default og image URL. - */ - public function getDefaultShareableImageUrl() : string { + public function buildUri(?EntityInterface $entity): ?string { $module = $this->moduleHandler->getModule('helfi_platform_config'); $current_language = $this->languageManager ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); @@ -55,10 +43,7 @@ public function getDefaultShareableImageUrl() : string { $image_file_name = $current_language === 'sv' ? 'og-global-sv.png' : 'og-global.png'; return $this->fileUrlGenerator - ->generate("{$module->getPath()}/fixtures/{$image_file_name}") - ->setAbsolute(TRUE) - ->toString(TRUE) - ->getGeneratedUrl(); + ->generateAbsoluteString("{$module->getPath()}/fixtures/{$image_file_name}"); } } diff --git a/src/Token/OGImageBuilderInterface.php b/src/Token/OGImageBuilderInterface.php index 496c26c32..cb84b8ae3 100644 --- a/src/Token/OGImageBuilderInterface.php +++ b/src/Token/OGImageBuilderInterface.php @@ -12,23 +12,23 @@ interface OGImageBuilderInterface { /** * Checks whether this builder is applicable for given entity. * - * @param \Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface|null $entity * An entity to check. * * @return bool * TRUE if this instance should handle the given entity. */ - public function applies(EntityInterface $entity) : bool; + public function applies(?EntityInterface $entity) : bool; /** * Generate image URI. * - * @param \Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface|null $entity * Entity to use for generation. * * @return string|null * Image uri or NULL on failure. */ - public function buildUri(EntityInterface $entity) : ?string; + public function buildUri(?EntityInterface $entity) : ?string; } diff --git a/src/Token/OGImageManager.php b/src/Token/OGImageManager.php index 4e5d2c574..21d5032b2 100644 --- a/src/Token/OGImageManager.php +++ b/src/Token/OGImageManager.php @@ -56,13 +56,13 @@ public function add(OGImageBuilderInterface $builder, int $priority = 0) : void /** * Builds image url for given entity. * - * @param \Drupal\Core\Entity\EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface|null $entity * The entity. * * @return string|null * OG image url or NULL on failure. */ - public function buildUrl(EntityInterface $entity) : ?string { + public function buildUrl(?EntityInterface $entity) : ?string { $image_uri = NULL; foreach ($this->getBuilders() as $builder) { From c5a3cb8dc8a35767b4373ddd7b27339adfe33a89 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 14 Mar 2024 08:37:45 +0200 Subject: [PATCH 06/10] UHF-9712: More intuitive sorting order for builder --- helfi_platform_config.services.yml | 2 +- src/Token/OGImageManager.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/helfi_platform_config.services.yml b/helfi_platform_config.services.yml index e563f383c..8fe795bba 100644 --- a/helfi_platform_config.services.yml +++ b/helfi_platform_config.services.yml @@ -75,4 +75,4 @@ services: - '@language_manager' - '@file_url_generator' tags: - - { name: helfi_platform_config.og_image_builder, priority: 100 } + - { name: helfi_platform_config.og_image_builder, priority: -100 } diff --git a/src/Token/OGImageManager.php b/src/Token/OGImageManager.php index 21d5032b2..5e4a3cbcd 100644 --- a/src/Token/OGImageManager.php +++ b/src/Token/OGImageManager.php @@ -98,7 +98,7 @@ public function buildUrl(?EntityInterface $entity) : ?string { */ private function getBuilders() : array { if (empty($this->sortedBuilders)) { - krsort($this->builders); + ksort($this->builders); $this->sortedBuilders = array_merge(...$this->builders); } From 8ede79c18abf21be8653867a92d60d9a95ff814e Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Fri, 15 Mar 2024 15:07:31 +0200 Subject: [PATCH 07/10] UHF-9712: Move documentation to development.md --- documentation/development.md | 53 +++++++++++++++++++++++++++++++++++- documentation/tokens.md | 51 ---------------------------------- 2 files changed, 52 insertions(+), 52 deletions(-) delete mode 100644 documentation/tokens.md diff --git a/documentation/development.md b/documentation/development.md index 0bfecacae..869427a70 100644 --- a/documentation/development.md +++ b/documentation/development.md @@ -229,7 +229,7 @@ The update hook above will re-import all configuration from `helfi_media` module The `helfi_platform_config.config_update_helper` invokes `hook_rewrite_config_update`, which allows custom modules to react to config re-importing. -##### In this example we would want to override Text paragraph label with a configuration found in my_module. +##### In this example we would want to override Text paragraph label with a configuration found in my_module. To trigger the `hook_rewrite_config_update`, implement the hook to your `my_module.module`: ```php @@ -254,3 +254,54 @@ label: Teksti (ylikirjoitettu) ``` +## Tokens + +Helfi platform config implements `hook_tokens()`. With the help of `helfi_platform_config.og_image_manager` service, it provides `[*:shareable-image]` token. Modules may implement services that handle this token for their entity types. + +Modules that use this system should still implement `hook_tokens_info` to provide information about the implemented token. + +### Defining image builder service + +Add a new service: + +```yml +# yourmodule/yourmodule.services.yml + yourmodule.og_image.your_entity_type: + class: Drupal\yourmodule\Token\YourEntityImageBuilder + arguments: [] + tags: + - { name: helfi_platform_config.og_image_builder, priority: 100 } +``` + +```php +# yourmodule/src/Token/YourEntityImageBuilder.php +field_image->entity->getFileUri(); + } + +} +``` diff --git a/documentation/tokens.md b/documentation/tokens.md deleted file mode 100644 index ff6e5d59c..000000000 --- a/documentation/tokens.md +++ /dev/null @@ -1,51 +0,0 @@ -# Tokens - -Helfi platform config implements `hook_tokens()`, and with the help of `helfi_platform_config.og_image_manager`, the `[*:shareable-image]` token is provided. Modules may implement services that handle this token for their entity types. - -Modules should still implement `hook_tokens_info` to provide information about the implemented token. - -## Defining image builder service - -Add a new service: - -```yml -# yourmodule/yourmodule.services.yml - yourmodule.og_image.your_entity_type: - class: Drupal\yourmodule\Token\YourEntityImageBuilder - arguments: [] - tags: - - { name: helfi_platform_config.og_image_builder, priority: 100 } -``` - -```php -# yourmodule/src/Token/YourEntityImageBuilder.php -field_image->entity->toUrl(); - } - -} -``` From b587246af90902ee056a374893bcf0a721503e0f Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Tue, 12 Mar 2024 12:25:23 +0200 Subject: [PATCH 08/10] UHF-9712: Add tests --- tests/src/Functional/EntityOgImageTest.php | 111 +++++++++++++++++++++ tests/src/Unit/OGImageManagerTest.php | 99 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 tests/src/Functional/EntityOgImageTest.php create mode 100644 tests/src/Unit/OGImageManagerTest.php diff --git a/tests/src/Functional/EntityOgImageTest.php b/tests/src/Functional/EntityOgImageTest.php new file mode 100644 index 000000000..ecdc7e8bc --- /dev/null +++ b/tests/src/Functional/EntityOgImageTest.php @@ -0,0 +1,111 @@ +getTestFiles('image')[0]->uri; + + $file = File::create([ + 'uri' => $uri, + ]); + $file->save(); + + $media = Media::create([ + 'bundle' => 'image', + 'name' => 'Custom name', + 'field_media_image' => $file->id(), + ]); + $media->save(); + + $node = $this->drupalCreateNode([ + 'title' => 'title', + 'langcode' => 'fi', + 'bundle' => 'page', + 'status' => 1, + ]); + $node->save(); + + // Global image style is used when media field is not set. + $this->drupalGet($node->toUrl('canonical')); + $this->assertGlobalOgImage('fi'); + + // Media is used when 'field_liftup_image' is set. + $node->set('field_liftup_image', $media->id()); + $node->save(); + $this->drupalGet($node->toUrl('canonical')); + $this->assertImageStyle(); + + $unit = Unit::create([ + 'id' => 123, + 'title' => 'title', + 'langcode' => 'sv', + 'bundle' => 'tpr_unit', + ]); + $unit->save(); + + // Global image style is used when media field is not set. + $this->drupalGet($unit->toUrl('canonical')); + $this->assertGlobalOgImage('sv'); + + // Picture url override is used. + $unit->set('picture_url_override', $media->id()); + $unit->save(); + $this->drupalGet($unit->toUrl('canonical')); + $this->assertImageStyle(); + } + + /** + * Assert that og_image image style was used. + */ + private function assertImageStyle() : void { + $this->assertSession()->elementAttributeContains('css', 'meta[property="og:image"]', 'content', 'styles/og_image'); + } + + /** + * Assert that global og image was used. + * + * @param string $langcode + * Content langcode. + */ + private function assertGlobalOgImage(string $langcode) : void { + $og_image_file = match($langcode) { + 'sv' => 'og-global-sv.png', + default => 'og-global.png', + }; + + $this->assertSession()->elementAttributeContains('css', 'meta[property="og:image"]', 'content', $og_image_file); + $this->assertSession()->elementAttributeNotContains('css', 'meta[property="og:image"]', 'content', 'styles/og_image'); + } + +} diff --git a/tests/src/Unit/OGImageManagerTest.php b/tests/src/Unit/OGImageManagerTest.php new file mode 100644 index 000000000..30119e67b --- /dev/null +++ b/tests/src/Unit/OGImageManagerTest.php @@ -0,0 +1,99 @@ +getSut(); + $entity = $this->prophesize(EntityInterface::class)->reveal(); + + // First builder does not apply. + $sut->add($this->createImageBuilderMock('https://1', FALSE)->reveal()); + $this->assertEquals(NULL, $sut->buildUrl($entity)); + + // Second builder applies but returns NULL. + $sut->add($this->createImageBuilderMock(NULL)->reveal()); + $this->assertEquals(NULL, $sut->buildUrl($entity)); + + // Third builder applies, priority is lower. + $sut->add($this->createImageBuilderMock('https://3')->reveal(), -10); + $this->assertEquals('https://3', $sut->buildUrl($entity)); + + // Builder with the lowers priority gets overwritten by '3'. + $builder4 = $this->createImageBuilderMock('https://4'); + $sut->add($builder4->reveal(), -100); + $this->assertEquals('https://3', $sut->buildUrl($entity)); + $builder4->buildUri(Argument::any())->shouldHaveBeenCalled(); + } + + /** + * Gets service under test. + * + * @param \Drupal\Core\File\FileUrlGeneratorInterface|null $fileUrlGenerator + * File url generator mock. + * + * @returns \Drupal\helfi_platform_config\Token\OGImageManager + * The open graph image manager. + */ + private function getSut(?FileUrlGeneratorInterface $fileUrlGenerator = NULL) : OGImageManager { + $moduleHandler = $this->prophesize(ModuleHandlerInterface::class); + + if (!$fileUrlGenerator) { + $prophecy = $this->prophesize(FileUrlGeneratorInterface::class); + $prophecy->generateAbsoluteString(Argument::any())->willReturnArgument(0); + $fileUrlGenerator = $prophecy->reveal(); + } + + return new OGImageManager( + $moduleHandler->reveal(), + $fileUrlGenerator, + ); + } + + /** + * Creates mock image builder. + * + * @param string|null $url + * Return value for buildUrl(). + * @param bool $applies + * Return value for applies(). + * + * @return \Drupal\helfi_platform_config\Token\OGImageBuilderInterface|\Prophecy\Prophecy\ObjectProphecy + * Builder mock. + */ + private function createImageBuilderMock(?string $url, bool $applies = TRUE) : OGImageBuilderInterface|ObjectProphecy { + $builder = $this->prophesize(OGImageBuilderInterface::class); + $builder->applies(Argument::any())->willReturn($applies); + $builder->buildUri(Argument::any())->willReturn($url); + return $builder; + } + +} From c9d6b9ad8d6bfebea85715354268067756d26898 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 18 Mar 2024 09:29:52 +0200 Subject: [PATCH 09/10] UHF-9712: Add missing declare(strict_types=1) --- modules/helfi_tpr_config/src/Entity/Unit.php | 2 ++ src/Token/OGImageBuilderInterface.php | 2 ++ src/Token/OGImageManager.php | 2 ++ 3 files changed, 6 insertions(+) diff --git a/modules/helfi_tpr_config/src/Entity/Unit.php b/modules/helfi_tpr_config/src/Entity/Unit.php index 35e267e0a..af2add89e 100644 --- a/modules/helfi_tpr_config/src/Entity/Unit.php +++ b/modules/helfi_tpr_config/src/Entity/Unit.php @@ -1,5 +1,7 @@ Date: Mon, 18 Mar 2024 09:31:44 +0200 Subject: [PATCH 10/10] UHF-9712: Move test to helfi_tpr_config --- .../tests}/src/Functional/EntityOgImageTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {tests => modules/helfi_tpr_config/tests}/src/Functional/EntityOgImageTest.php (97%) diff --git a/tests/src/Functional/EntityOgImageTest.php b/modules/helfi_tpr_config/tests/src/Functional/EntityOgImageTest.php similarity index 97% rename from tests/src/Functional/EntityOgImageTest.php rename to modules/helfi_tpr_config/tests/src/Functional/EntityOgImageTest.php index ecdc7e8bc..2c10b1308 100644 --- a/tests/src/Functional/EntityOgImageTest.php +++ b/modules/helfi_tpr_config/tests/src/Functional/EntityOgImageTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Drupal\Tests\helfi_platform_config\Functional; +namespace Drupal\Tests\helfi_tpr_config\Functional; use Drupal\file\Entity\File; use Drupal\helfi_tpr\Entity\Unit;