feat: Adiciona field type social_link para redes sociais do usuário

Implementa o field type 'social_link' com seletor de rede e URL de
perfil, composto por:

- SocialLinkItem: field type com colunas 'network' (varchar 64) e
  'url' (varchar 2048), cardinalidade ilimitada
- SocialLinkWidget: widget com select de rede e input de URL
- SocialLinkFormatter: formatter que renderiza links com classe CSS
  por rede (social-link--{network}), target _blank e rel noopener
- config/optional: field.storage e field.field para user
- config/translations/pt-br: tradução do label e description
- hook_install e update_10002: configura form/view displays
- UserInfoBlock: expõe social_links via getSocialLinks()
- Template: adiciona seção de redes sociais e remove referências
  obsoletas a category e dept_code
- translations/site_users.pt-br.po: strings do novo field type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 14:10:28 -03:00
parent 1dafd4a865
commit 8bab0515e1
11 changed files with 383 additions and 31 deletions

View File

@@ -109,9 +109,8 @@ class UserInfoBlock extends BlockBase implements ContainerFactoryPluginInterface
'username' => $user->getDisplayName(),
'name' => $this->getFieldValue($user, 'field_user_name'),
'phone' => $this->getFieldValue($user, 'field_user_phone'),
'bio' => $this->getFieldValue($user, 'field_user_bio'),
'social_links' => $this->getSocialLinks($user),
'photo_url' => $default_photo_url,
'photo_alt' => $default_photo ? $default_photo->label() : '',
];
@@ -150,6 +149,34 @@ class UserInfoBlock extends BlockBase implements ContainerFactoryPluginInterface
return NULL;
}
/**
* Returns the social network links of a user.
*
* @param \Drupal\user\UserInterface $user
* The user entity.
*
* @return array
* Array of items with 'network' and 'url' keys.
*/
protected function getSocialLinks(UserInterface $user): array {
$links = [];
if (!$user->hasField('field_user_social_links') || $user->get('field_user_social_links')->isEmpty()) {
return $links;
}
foreach ($user->get('field_user_social_links') as $item) {
if (!$item->isEmpty()) {
$links[] = [
'network' => $item->network,
'url' => $item->url,
];
}
}
return $links;
}
/**
* Obtém o valor de um campo do usuário.
*

View File

@@ -0,0 +1,52 @@
<?php
namespace Drupal\site_users\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Url;
use Drupal\site_users\Plugin\Field\FieldType\SocialLinkItem;
/**
* Plugin implementation of the 'social_link_formatter' formatter.
*
* @FieldFormatter(
* id = "social_link_formatter",
* label = @Translation("Social link"),
* field_types = {
* "social_link"
* }
* )
*/
class SocialLinkFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode): array {
$elements = [];
$networks = SocialLinkItem::getNetworks();
foreach ($items as $delta => $item) {
if ($item->isEmpty()) {
continue;
}
$network_label = $networks[$item->network] ?? $item->network;
$elements[$delta] = [
'#type' => 'link',
'#title' => $network_label,
'#url' => Url::fromUri($item->url),
'#attributes' => [
'class' => ['social-link', 'social-link--' . $item->network],
'target' => '_blank',
'rel' => 'noopener noreferrer',
],
];
}
return $elements;
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace Drupal\site_users\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
/**
* Plugin implementation of the 'social_link' field type.
*
* @FieldType(
* id = "social_link",
* label = @Translation("Social link"),
* description = @Translation("Stores a social network type and profile URL."),
* default_widget = "social_link_widget",
* default_formatter = "social_link_formatter"
* )
*/
class SocialLinkItem extends FieldItemBase {
/**
* Returns the list of available social networks.
*
* @return array
* Associative array keyed by machine name, valued by label.
*/
public static function getNetworks(): array {
return [
'facebook' => 'Facebook',
'instagram' => 'Instagram',
'linkedin' => 'LinkedIn',
'twitter' => 'X (Twitter)',
'youtube' => 'YouTube',
'github' => 'GitHub',
'tiktok' => 'TikTok',
'telegram' => 'Telegram',
'whatsapp' => 'WhatsApp',
'pinterest' => 'Pinterest',
];
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition): array {
$properties['network'] = DataDefinition::create('string')
->setLabel(t('Network'))
->setRequired(TRUE);
$properties['url'] = DataDefinition::create('uri')
->setLabel(t('URL'))
->setRequired(TRUE);
return $properties;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition): array {
return [
'columns' => [
'network' => [
'type' => 'varchar',
'length' => 64,
],
'url' => [
'type' => 'varchar',
'length' => 2048,
],
],
];
}
/**
* {@inheritdoc}
*/
public function isEmpty(): bool {
return empty($this->get('network')->getValue())
|| empty($this->get('url')->getValue());
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Drupal\site_users\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\site_users\Plugin\Field\FieldType\SocialLinkItem;
/**
* Plugin implementation of the 'social_link_widget' widget.
*
* @FieldWidget(
* id = "social_link_widget",
* label = @Translation("Social link"),
* field_types = {
* "social_link"
* }
* )
*/
class SocialLinkWidget extends WidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state): array {
$item = $items[$delta];
$element['network'] = [
'#type' => 'select',
'#title' => $this->t('Network'),
'#options' => ['' => $this->t('- Select -')] + SocialLinkItem::getNetworks(),
'#default_value' => $item->network ?? '',
];
$element['url'] = [
'#type' => 'url',
'#title' => $this->t('Profile URL'),
'#default_value' => $item->url ?? '',
'#maxlength' => 2048,
'#placeholder' => 'https://',
];
return $element;
}
}