View source
<?php
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldFilteredMarkup;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\WidgetInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Template\Attribute;
use Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget;
use Drupal\paragraphs_sets\Entity\ParagraphsSet;
use Drupal\paragraphs_sets\ParagraphsSets;
const PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE = '_none';
function paragraphs_sets_theme() {
return [
'field_multiple_value_form__paragraphs_sets' => [
'render element' => 'element',
'path' => drupal_get_path('module', 'paragraphs_sets') . '/templates',
],
'paragraphs_sets_add_dialog' => [
'render element' => 'element',
'path' => drupal_get_path('module', 'paragraphs_sets') . '/templates',
],
];
}
function paragraphs_sets_field_widget_settings_summary_alter(&$summary, $context) {
if ($context['widget'] instanceof ParagraphsWidget) {
$settings = $context['widget']
->getThirdPartySettings('paragraphs_sets');
if (isset($settings['paragraphs_sets']['use_paragraphs_sets']) && $settings['paragraphs_sets']['use_paragraphs_sets']) {
$summary[] = t('Show Paragraphs Sets');
}
$field_definition = $context['field_definition'];
$field_allowed_paragraphs_types = $context['widget']
->getAllowedTypes($field_definition);
$cardinality = $field_definition
->getFieldStorageDefinition()
->getCardinality();
$sets_options = ParagraphsSets::getSetsOptions(array_keys($field_allowed_paragraphs_types), $cardinality);
if ($settings['paragraphs_sets']['use_paragraphs_sets'] ?? FALSE) {
$sets_allowed = array_filter($settings['paragraphs_sets']['sets_allowed'] ?? []);
if ($sets_allowed) {
$sets_allowed_summary = implode(', ', array_intersect_key($sets_options, $sets_allowed));
$summary[] = t('Limit sets to: @sets', [
'@sets' => $sets_allowed_summary,
]);
}
}
$default_set = $settings['paragraphs_sets']['default_set'] ?? PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE;
if ($default_set !== PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE && isset($sets_options[$default_set])) {
$summary[] = t('Default set: @set', [
'@set' => $sets_options[$default_set],
]);
}
}
}
function paragraphs_sets_field_widget_third_party_settings_form(WidgetInterface $plugin, FieldDefinitionInterface $field_definition, $form_mode, $form, FormStateInterface $form_state) {
if ($plugin instanceof ParagraphsWidget) {
$settings = $plugin
->getThirdPartySettings('paragraphs_sets');
$element['paragraphs_sets'] = [
'#type' => 'fieldgroup',
'#title' => t('Paragraphs Sets'),
'#attributes' => [
'class' => [
'fieldgroup',
'form-composite',
],
],
];
$element['paragraphs_sets']['use_paragraphs_sets'] = [
'#type' => 'checkbox',
'#title' => t('Enable Paragraphs Sets'),
'#default_value' => isset($settings['paragraphs_sets']['use_paragraphs_sets']) ? $settings['paragraphs_sets']['use_paragraphs_sets'] : '',
];
$paragraph_field = $field_definition
->getName();
$field_allowed_paragraphs_types = $plugin
->getAllowedTypes($field_definition);
$cardinality = $field_definition
->getFieldStorageDefinition()
->getCardinality();
$sets_options = ParagraphsSets::getSetsOptions(array_keys($field_allowed_paragraphs_types), $cardinality);
$element['paragraphs_sets']['sets_allowed'] = [
'#type' => 'checkboxes',
'#title' => t('Limit sets to'),
'#description' => t('Leave unchecked to show all. Sets not shown here are not available due to field restrictions on cardinality or Paragraph types.'),
'#options' => $sets_options,
'#default_value' => isset($settings['paragraphs_sets']['sets_allowed']) ? $settings['paragraphs_sets']['sets_allowed'] : [],
'#states' => [
'visible' => [
":input[name='fields[{$paragraph_field}][settings_edit_form][third_party_settings][paragraphs_sets][paragraphs_sets][use_paragraphs_sets]']" => [
'checked' => TRUE,
],
],
],
];
$element['paragraphs_sets']['default_set'] = [
'#type' => 'select',
'#title' => t('Default set'),
'#description' => t('Choose a default set. The "Default paragraph type" setting above must be set to "- None -".'),
'#options' => array_merge([
PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE => t("- None -"),
], $sets_options),
'#default_value' => isset($settings['paragraphs_sets']['default_set']) ? $settings['paragraphs_sets']['default_set'] : '',
'#states' => [
'visible' => [
":input[name='fields[{$paragraph_field}][settings_edit_form][third_party_settings][paragraphs_sets][paragraphs_sets][use_paragraphs_sets]']" => [
'checked' => TRUE,
],
],
'enabled' => [
":input[name='fields[{$paragraph_field}][settings_edit_form][settings][default_paragraph_type]']" => [
'value' => '_none',
],
],
],
];
return $element;
}
}
function paragraphs_sets_field_widget_multivalue_form_alter(array &$elements, FormStateInterface $form_state, array $context) {
$widget = $context['widget'];
if (!$widget instanceof ParagraphsWidget) {
return;
}
$items = $context['items'];
$host = $context['items']
->getEntity();
$form = $context['form'];
$widget_settings = $widget
->getSettings();
$field_definition = $items
->getFieldDefinition();
$field_name = $field_definition
->getName();
$field_parents = $form['#parents'];
$field_state = ParagraphsSets::getWidgetState($field_parents, $field_name, $form_state);
$is_multiple = $field_definition
->getFieldStorageDefinition()
->isMultiple();
$cardinality = $field_definition
->getFieldStorageDefinition()
->getCardinality();
$field_title = $field_definition
->getLabel();
$description = FieldFilteredMarkup::create(\Drupal::token()
->replace($field_definition
->getDescription()));
$user_input =& $form_state
->getUserInput();
$max = $field_state['items_count'];
$entity_type_manager = \Drupal::entityTypeManager();
$field_allowed_paragraphs_types = $widget
->getAllowedTypes($field_definition);
$sets = ParagraphsSets::getSets(array_keys($field_allowed_paragraphs_types));
$widget_third_party_settings = $widget
->getThirdPartySetting('paragraphs_sets', 'paragraphs_sets', []);
if (isset($widget_third_party_settings['sets_allowed']) && count(array_filter($widget_third_party_settings['sets_allowed']))) {
$sets = array_intersect_key($sets, array_filter($widget_third_party_settings['sets_allowed']));
}
$set = isset($field_state['selected_set']) ? $field_state['selected_set'] : NULL;
if ($max == 0 && $items
->getEntity()
->isNew() && empty($set)) {
$default_set = $widget_third_party_settings['default_set'] ?? PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE;
if ($default_set !== PARAGRAPHS_SETS_DEFAULT_EMPTY_VALUE && isset($sets[$default_set]) && isset($sets[$default_set]['paragraphs']) && ($cardinality === FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($sets[$default_set]['paragraphs']) <= $cardinality)) {
$set = $default_set;
}
}
if ($set && isset($sets[$set])) {
if (isset($field_state['button_type']) && 'set_selection_button' === $field_state['button_type']) {
$items
->filter(function () {
return FALSE;
});
$field_state['paragraphs'] = [];
foreach ($user_input[$field_name] as $key => $value) {
if (!is_numeric($key) || empty($value['subform'])) {
continue;
}
unset($user_input[$field_name][$key]);
}
$field_state['items_count'] = 0;
foreach (Element::children($elements) as $element_key) {
if (is_numeric($element_key)) {
unset($elements[$element_key]);
}
}
$max = 0;
}
$target_type = $field_definition
->getSetting('target_type');
$context = [
'set' => $set,
'field' => $field_definition,
'form' => $form,
'form_state' => $form_state,
'entity' => $host,
];
$insert_delta = isset($user_input[$field_name]['add_more']['add_modal_form_area']['add_more_delta']) ? $user_input[$field_name]['add_more']['add_modal_form_area']['add_more_delta'] : NULL;
foreach ($sets[$set]['paragraphs'] as $key => $info) {
$alter_hooks = [
'paragraphs_set_data',
'paragraphs_set_' . $set . '_data',
'paragraphs_set_' . $set . '_' . $field_name . '_data',
];
$context['key'] = $key;
$context['paragraphs_bundle'] = $info['type'];
$data = empty($info['data']) ? [] : $info['data'];
\Drupal::moduleHandler()
->alter($alter_hooks, $data, $context);
$item_values = [
'type' => $info['type'],
] + $data;
$max++;
if (isset($insert_delta)) {
ParagraphsSets::prepareDeltaPosition($field_state, $form_state, [
$field_name,
], $insert_delta);
$insert_delta++;
}
$paragraphs_entity = $entity_type_manager
->getStorage($target_type)
->create($item_values);
$display = EntityFormDisplay::collectRenderDisplay($paragraphs_entity, $field_definition
->getSetting('form_display_mode'));
$field_state['paragraphs'][$max - 1] = [
'entity' => $paragraphs_entity,
'display' => $display,
'mode' => isset($widget_settings['edit_mode']) && $widget_settings['edit_mode'] === 'open' ? 'edit' : 'closed',
'original_delta' => $max,
];
}
$field_state['items_count'] = $max;
$field_state['real_item_count'] = $max;
$field_state['selected_set'] = NULL;
ParagraphsSets::setWidgetState($field_parents, $field_name, $form_state, $field_state);
}
if ($max > 0) {
for ($delta = 0; $delta < $max; $delta++) {
if (!isset($items[$delta])) {
$items
->appendItem();
}
$element_base = [
'#title' => $is_multiple ? '' : $field_title,
'#description' => $is_multiple ? '' : $description,
'#paragraphs_bundle' => '',
];
$element_base += [
'#field_parents' => $form['#parents'],
'#required' => $delta == 0 && $field_definition
->isRequired(),
'#delta' => $delta,
'#weight' => $delta,
];
$element = $widget
->formElement($items, $delta, $element_base, $form, $form_state);
if ($element) {
$widget_state = ParagraphsSets::getWidgetState($element['#field_parents'], $field_name, $form_state);
$element['#paragraphs_bundle'] = $widget_state['paragraphs'][$delta]['entity']
->bundle();
$context = [
'form' => $form,
'widget' => $widget,
'items' => $items,
'delta' => $delta,
'default' => (bool) $form_state
->get('default_value_widget'),
];
\Drupal::moduleHandler()
->alter([
'field_widget_form',
'field_widget_' . $widget
->getPluginId() . '_form',
], $element, $form_state, $context);
if ($is_multiple) {
$element['_weight'] = [
'#type' => 'weight',
'#title' => t('Weight for row @number', [
'@number' => $delta + 1,
]),
'#title_display' => 'invisible',
'#delta' => $max,
'#default_value' => $items[$delta]->_weight ?: $delta,
'#weight' => 100,
];
}
if (isset($element['#access']) && !$element['#access']) {
$field_state['items_count']--;
}
else {
$elements[$delta] = $element;
}
}
}
}
if ($cardinality !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && $field_state['items_count'] >= $cardinality) {
unset($elements['add_more']);
}
if (empty($widget_third_party_settings['use_paragraphs_sets'])) {
return;
}
$field_state = ParagraphsSets::getWidgetState($field_parents, $field_name, $form_state);
$field_state['real_item_count'] = $field_state['items_count'];
$field_state['add_mode'] = $widget
->getSetting('add_mode');
ParagraphsSets::setWidgetState($field_parents, $field_name, $form_state, $field_state);
if (isset($elements['#theme']) && 'field_multiple_value_form' === $elements['#theme']) {
$elements['#theme'] = 'field_multiple_value_form__paragraphs_sets';
}
if ('modal' === $field_state['add_mode']) {
$elements['add_more']['#theme'] = 'paragraphs_sets_add_dialog';
$elements['add_more']['#widget_title'] = $widget
->getSetting('title');
$elements['add_more']['#widget_title_plural'] = $widget
->getSetting('title_plural');
$cardinality = $field_definition
->getFieldStorageDefinition()
->getCardinality();
$field_id_prefix = implode('-', array_merge($field_parents, [
$field_name,
]));
$field_wrapper_id = Html::getId($field_id_prefix . '-add-more-wrapper');
foreach ($sets as $machine_name => $set) {
if ($cardinality !== FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && count($set['paragraphs']) > $cardinality) {
continue;
}
$button_key = 'append_selection_button_' . $machine_name;
$elements['add_more'][$button_key] = ParagraphsWidget::expandButton([
'#type' => 'submit',
'#name' => $field_id_prefix . '_' . $machine_name . '_set_set',
'#value' => $set['label'],
'#attributes' => [
'class' => [
'field-add-more-submit',
'field-append-set-submit',
],
],
'#limit_validation_errors' => [
array_merge($field_parents, [
$field_definition
->getName(),
'set_set',
]),
],
'#submit' => [
[
'Drupal\\paragraphs_sets\\ParagraphsSets',
'setSetSubmit',
],
],
'#ajax' => [
'callback' => [
'Drupal\\paragraphs_sets\\ParagraphsSets',
'setSetAjax',
],
'wrapper' => $field_wrapper_id,
],
'#set_machine_name' => $machine_name,
]);
}
}
$context['widget'] = $widget;
$elements['set_selection'] = ParagraphsSets::buildSelectSetSelection($elements, $context, $form_state, $set);
$elements['#attached']['library'][] = 'paragraphs_sets/drupal.paragraphs_sets.admin';
}
function paragraphs_sets_preprocess_field_multiple_value_form__paragraphs_sets(&$variables) {
$element = $variables['element'];
$variables['multiple'] = $element['#cardinality_multiple'];
if ($variables['multiple']) {
$table_id = Html::getUniqueId($element['#field_name'] . '_values');
$order_class = $element['#field_name'] . '-delta-order';
$rows = [];
$items = [];
$variables['button'] = [];
$variables['selection'] = [];
foreach (Element::children($element) as $key) {
if ($key === 'add_more') {
$variables['button'] =& $element[$key];
}
elseif ($key === 'set_selection') {
$variables['selection'] =& $element[$key];
}
elseif ($key === 'header_actions') {
$variables['header_actions'] =& $element[$key];
}
elseif (!empty($element[$key]['#paragraphs_bundle'])) {
$items[] =& $element[$key];
}
}
usort($items, '_field_multiple_value_form_sort_helper');
foreach ($items as $item) {
$item['_weight']['#attributes']['class'] = [
$order_class,
];
$item['#attributes']['data-paragraphs-bundle'] = $item['#paragraphs_bundle'];
$delta_element = $item['_weight'];
unset($item['_weight']);
$cells = [
[
'data' => '',
'class' => [
'field-multiple-drag',
],
],
[
'data' => $item,
],
[
'data' => $delta_element,
'class' => [
'delta-order',
],
],
];
$rows[] = [
'data' => $cells,
'class' => [
'draggable',
'paragraphs-item',
Html::getClass("paragraphs-item--{$item['#paragraphs_bundle']}"),
],
];
}
$header_attributes = new Attribute([
'class' => [
'label',
],
]);
if (!empty($element['#required'])) {
$header_attributes['class'][] = 'js-form-required';
$header_attributes['class'][] = 'form-required';
}
$header = [
[
'data' => [
'#prefix' => '<h4' . $header_attributes . '>',
'#markup' => $element['#title'],
'#suffix' => '</h4>',
],
'colspan' => 2,
'class' => [
'field-label',
],
],
t('Order', [], [
'context' => 'Sort order',
]),
];
if (!empty($variables['header_actions'])) {
$header[0]['data'] = [
'title' => $header[0]['data'],
'button' => $variables['header_actions'],
];
}
$variables['table'] = [
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
'#attributes' => [
'id' => $table_id,
'class' => [
'field-multiple-table',
],
],
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => $order_class,
],
],
];
if (!empty($element['#description'])) {
$description_id = $element['#attributes']['aria-describedby'];
$description_attributes['id'] = $description_id;
$variables['description']['attributes'] = new Attribute($description_attributes);
$variables['description']['content'] = $element['#description'];
$variables['table']['#attributes']['aria-describedby'] = $element['#attributes']['aria-describedby'];
}
}
else {
$variables['elements'] = [];
$variables['selection'] = [];
foreach (Element::children($element) as $key) {
if ($key === 'set_selection') {
$variables['selection'] =& $element[$key];
}
else {
$variables['elements'][] = $element[$key];
}
}
}
call_user_func_array('paragraphs_preprocess_field_multiple_value_form', [
&$variables,
]);
}
function template_preprocess_paragraphs_sets_add_dialog(array &$variables) {
$variables += [
'buttons' => [],
'buttons_title' => $variables['element']['#widget_title_plural'],
'sets' => [],
'sets_title' => t('@title sets', [
'@title' => $variables['element']['#widget_title'],
]),
];
foreach (Element::children($variables['element']) as $key) {
if ($key == 'add_modal_form_area') {
$variables['add'] = $variables['element'][$key];
}
elseif (strpos($key, 'append_selection_button_') === 0) {
$variables['sets'][$key] = $variables['element'][$key];
}
else {
$variables['buttons'][$key] = $variables['element'][$key];
}
}
}
function paragraphs_set_load($name) {
return ParagraphsSet::load($name);
}