gutenberg.module in Gutenberg 8.2
Same filename and directory in other branches
Provides integration with the Gutenberg editor.
File
gutenberg.moduleView source
<?php
/**
* @file
* Provides integration with the Gutenberg editor.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\gutenberg\Controller\UtilsController;
use Drupal\gutenberg\MappingFieldsHelper;
use Drupal\image\Entity\ImageStyle;
use Drupal\media\MediaForm;
use Drupal\node\NodeInterface;
use Drupal\views\ViewExecutable;
// <editor-fold desc="Gutenberg autogenerated code.">
define('GUTENBERG_JS_VERSION', '8.4.0');
define('GUTENBERG_JS_GIT_COMMIT', '83f36e40d7a7ab0b2b9df7ea1036abeb15122f55');
// </editor-fold>
/**
* Implements hook_theme().
*/
function gutenberg_theme() {
$templates = [
'page__node__edit__gutenberg' => [
'template' => 'page--node--edit--gutenberg',
],
'page__node__add__gutenberg' => [
'template' => 'page--node--add--gutenberg',
],
'node_edit_form__gutenberg' => [
'template' => 'node-edit-form--gutenberg',
],
// Gutenberg text field.
'field_gutenberg_text' => [
'render element' => 'element',
'file' => 'gutenberg.theme.inc',
],
'gutenberg_block' => [
'variables' => [
'block_name' => NULL,
'block_attributes' => [],
'block_content' => NULL,
],
'file' => 'gutenberg.theme.inc',
],
];
// Generate theme definitions for each module's dynamic block.
/*
* By default, Drupal 8 does not include theme suggestions from inside the
* module in which they were created, so we must add them manually here.
*/
$base_hook = 'gutenberg_block';
/** @var \Drupal\gutenberg\GutenbergLibraryManagerInterface $gutenberg_library_manager */
$gutenberg_library_manager = \Drupal::service('plugin.manager.gutenberg.library');
foreach ($gutenberg_library_manager
->getModuleDefinitions() as $module => $definition) {
if (empty($definition['dynamic-blocks'])) {
// No dynamic blocks to declare.
continue;
}
$template_hooks = drupal_find_theme_templates($templates, '.html.twig', drupal_get_path('module', $module) . '/templates');
foreach ($definition['dynamic-blocks'] as $block_name => $block_theme_definition) {
$block_name = str_replace('-', '_', $block_name);
$block_parts = explode('/', $block_name);
$hook_names = [
$block_parts[0],
];
if (count($block_parts) === 2) {
// namespace/blockname.
$hook_names[] = $block_parts[0] . '__' . $block_parts[1];
}
foreach ($hook_names as $hook_name) {
$theme_hook_name = $base_hook . '__' . $hook_name;
if (!isset($templates[$theme_hook_name]) && isset($template_hooks[$theme_hook_name])) {
// Add the module's theme definition if the template exists.
$template_hooks[$theme_hook_name]['type'] = 'module';
$templates[$theme_hook_name] = $block_theme_definition + $template_hooks[$theme_hook_name];
}
}
}
}
return $templates;
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function gutenberg_theme_suggestions_gutenberg_block(array $variables) {
$block_name = str_replace('-', '_', $variables['block_name']);
$block_parts = explode('/', $block_name);
$suggestions = [];
$base_hook = 'gutenberg_block__';
$suggestions[] = $base_hook . $block_parts[0];
if (count($block_parts) === 2) {
// namespace/blockname format.
$suggestions[] = $base_hook . $block_parts[0] . '__' . $block_parts[1];
}
return $suggestions;
}
/**
* Implements hook_form_alter().
*/
function gutenberg_form_alter(&$form, FormStateInterface $form_state, $form_id) {
/* TODO: Simplify large alter functions like this using specific classes:
* https://drupal.stackexchange.com/questions/238341
* @see content_moderation_form_alter()
*/
$form_object = $form_state
->getFormObject();
if ($form_object instanceof MediaForm && $form_object
->getOperation() === 'edit') {
_gutenberg_media_form_alter($form, $form_state, $form_id);
}
if ($form_id == 'node_type_edit_form' || $form_id == 'node_type_add_form') {
$config = \Drupal::service('config.factory')
->getEditable('gutenberg.settings');
$form['gutenberg'] = [
'#type' => 'details',
'#title' => t('Gutenberg experience'),
'#description' => '',
'#group' => 'additional_settings',
'#weight' => 999,
'enable_gutenberg_experience' => [
'#type' => 'checkbox',
'#title' => t('Enable Gutenberg experience'),
'#description' => t('Turn the node edit form into a full Gutenberg UI experience. At least one field of long text type is necessary.'),
'#default_value' => $config
->get($form['type']['#default_value'] . '_enable_full'),
],
];
$form['gutenberg']['categories'] = [
'#type' => 'hidden',
'#default_value' => [],
];
$example_code = '<code>
<pre>[
["core/heading", {}],
["core/paragraph", {"placeholder": "Insert text"}]
]</pre></code>';
$form['gutenberg']['gutenberg_template'] = [
'#type' => 'textarea',
'#description' => t('JSON structure of blocks. Example: @example_code', [
'@example_code' => Markup::create($example_code),
]),
'#title' => t('Template'),
'#default_value' => $config
->get($form['type']['#default_value'] . '_template'),
'#states' => [
'visible' => [
'input[name="enable_gutenberg_experience"]' => [
'checked' => TRUE,
],
],
],
];
/*
* TODO add validation on this.
* Enforcing the "None" lock if the template is empty.
*/
$form['gutenberg']['gutenberg_template_lock'] = [
'#type' => 'select',
'#title' => t('Template lock'),
'#description' => t('<code>All</code> will fully lock the page template, not able to delete, create or move blocks just edit the content.<br/><code>Insert</code> will allow moving blocks.'),
'#default_value' => $config
->get($form['type']['#default_value'] . '_template_lock'),
'#options' => [
'none' => t('None'),
'insert' => t('Insert'),
'all' => t('All'),
],
'#states' => [
'visible' => [
'input[name="enable_gutenberg_experience"]' => [
'checked' => TRUE,
],
],
],
];
$form['gutenberg']['allowed_blocks_details'] = [
'#type' => 'details',
'#title' => t('Allowed Gutenberg blocks'),
'#states' => [
'visible' => [
'input[name="enable_gutenberg_experience"]' => [
'checked' => TRUE,
],
],
],
];
$settings = UtilsController::getAllowedBlocks();
$blocks_settings = UtilsController::getBlocksSettings();
foreach ($settings['categories'] as $category) {
$category['reference'] = str_replace('/', '-', $category['reference']);
$form['gutenberg']['categories']['#default_value'][] = $category['reference'];
$form['gutenberg']['allowed_blocks_details'][$category['reference']] = [
'#type' => 'fieldset',
'#title' => $category['name'],
];
$options = [
$category['reference'] . '/all' => t('All'),
];
foreach ($category['blocks'] as $block) {
if (!in_array($block['id'], $blocks_settings['blacklist'])) {
$options[$block['id']] = $block['name'];
}
}
$default_values = array_combine(array_map(function ($block) {
return $block['id'];
}, $category['blocks']), array_map(function ($block) {
return $block['default'] ? $block['id'] : 0;
}, $category['blocks']));
$config_values = $config
->get($form['type']['#default_value'] . '_allowed_blocks');
$form['gutenberg']['allowed_blocks_details'][$category['reference']]['allowed_blocks_' . $category['reference']] = [
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => array_merge($default_values, $config_values ? $config_values : []),
];
}
$form['gutenberg']['allowed_drupal_blocks_details'] = [
'#type' => 'details',
'#title' => t('Allowed Drupal blocks'),
'#states' => [
'visible' => [
'input[name="enable_gutenberg_experience"]' => [
'checked' => TRUE,
],
],
],
];
$blockManager = \Drupal::service('plugin.manager.block');
$contextRepository = \Drupal::service('context.repository');
// Get blocks definition
// $definitions = $blockManager->getDefinitionsForContexts($contextRepository->getAvailableContexts());
$definitions = $blockManager
->getFilteredDefinitions('block_ui', $contextRepository
->getAvailableContexts());
$groups = $blockManager
->getGroupedDefinitions($definitions);
$form['gutenberg']['categories_drupal'] = [
'#type' => 'hidden',
'#default_value' => [],
];
$default_values = array_fill_keys(array_map(function ($key) {
return str_replace('drupalblock/', '', $key);
}, $settings['default_drupal_blocks']), TRUE);
foreach ($groups as $key => $blocks) {
$group_reference = preg_replace('@[^a-z0-9-]+@', '_', strtolower($key));
$options = [];
$input_default_values = [];
foreach ($blocks as $key_block => $block) {
if (!in_array('drupalblock/' . $key_block, $blocks_settings['blacklist'])) {
$options[$key_block] = $block['admin_label'];
if (isset($default_values[$key_block]) && $default_values[$key_block]) {
$input_default_values[$key_block] = $key_block;
}
}
}
if (count($options) > 0) {
$form['gutenberg']['categories_drupal']['#default_value'][] = $group_reference;
$form['gutenberg']['allowed_drupal_blocks_details'][$group_reference] = [
'#type' => 'fieldset',
'#title' => $key,
];
$config_values = $config
->get($form['type']['#default_value'] . '_allowed_drupal_blocks');
$form['gutenberg']['allowed_drupal_blocks_details'][$group_reference]['allowed_drupal_blocks_' . $group_reference] = [
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => array_merge($input_default_values, $config_values ? $config_values : []),
];
}
}
$form['#attached']['library'][] = 'gutenberg/admin';
$form['actions']['submit']['#submit'][] = '_gutenberg_node_type_form_submit';
if (isset($form['actions']['save_continue']['#submit'])) {
$form['actions']['save_continue']['#submit'][] = '_gutenberg_node_type_form_submit';
}
}
}
/**
* Alters the node form submit.
*
* @param array $form
* The form definition array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
function _gutenberg_node_type_form_submit(array $form, FormStateInterface $form_state) {
$gutenberg_enabled = $form_state
->getValue('enable_gutenberg_experience');
$template = $form_state
->getValue('gutenberg_template');
$template_lock = $form_state
->getValue('gutenberg_template_lock');
$config = \Drupal::service('config.factory')
->getEditable('gutenberg.settings');
$config
->set($form_state
->getValue('type') . '_enable_full', $gutenberg_enabled)
->save();
if (!$gutenberg_enabled) {
$config
->clear($form_state
->getValue('type') . '_allowed_blocks')
->save();
$config
->clear($form_state
->getValue('type') . '_allowed_drupal_blocks')
->save();
$config
->clear($form_state
->getValue('type') . '_gutenberg_template')
->save();
$config
->clear($form_state
->getValue('type') . '_gutenberg_template_lock')
->save();
return;
}
// Save template settings.
$config
->set($form_state
->getValue('type') . '_template', $template)
->save();
$config
->set($form_state
->getValue('type') . '_template_lock', $template_lock)
->save();
// Save Gutenberg core blocks settings.
$categories = explode(' ', $form_state
->getValue('categories'));
$values = [];
foreach ($categories as $category) {
$values = array_merge($values, $form_state
->getValue('allowed_blocks_' . $category));
}
$config
->set($form_state
->getValue('type') . '_allowed_blocks', $values)
->save();
// Save Drupal blocks settings.
$categories = explode(' ', $form_state
->getValue('categories_drupal'));
$values = [];
foreach ($categories as $category) {
$values = array_merge($values, $form_state
->getValue('allowed_drupal_blocks_' . $category));
}
$config
->set($form_state
->getValue('type') . '_allowed_drupal_blocks', $values)
->save();
}
/**
* Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
*
* Hides mapping fields.
*/
function gutenberg_form_node_form_alter(&$form, FormStateInterface $form_state) {
$node = $form_state
->getFormObject()
->getEntity();
if (!_gutenberg_is_gutenberg_enabled($node)) {
// Leave early if Gutenberg is not enabled for this entity.
return;
}
$config = \Drupal::service('config.factory')
->get('gutenberg.settings');
$node_type = $node->type
->getString();
// Set template options to global var.
$gutenberg_template = json_decode($config
->get($node_type . '_template'));
$form['#attached']['drupalSettings']['gutenberg']['template'] = $gutenberg_template;
$form['#attached']['drupalSettings']['gutenberg']['template-lock'] = $config
->get($node_type . '_template_lock');
/* @var $mapping_fields \Drupal\gutenberg\MappingFieldsHelper */
$mapping_fields = \Drupal::service('class_resolver')
->getInstanceFromDefinition(MappingFieldsHelper::class);
$mapped_fields = $mapping_fields
->getMappedFields($gutenberg_template);
foreach ($mapped_fields as $item) {
$form[$item['field']]['#access'] = FALSE;
}
/** @var \Drupal\gutenberg\GutenbergLibraryManagerInterface $gutenberg_library_manager */
$gutenberg_library_manager = \Drupal::service('plugin.manager.gutenberg.library');
$module_definitions = $gutenberg_library_manager
->getModuleDefinitions();
foreach ($module_definitions as $module_definition) {
foreach ($module_definition['libraries-edit'] as $library) {
$form['#attached']['library'][] = $library;
}
}
$theme_support = [];
$theme_definitions = $gutenberg_library_manager
->getActiveThemeDefinitions();
foreach ($theme_definitions as $theme_definition) {
foreach ($theme_definition['libraries-edit'] as $library) {
$form['#attached']['library'][] = $library;
}
if (isset($theme_definition['theme-support'])) {
// Merge only the top level configuration, with the child theme
// taking precedence.
$theme_support = $theme_definition['theme-support'] + $theme_support;
}
}
$form['#attached']['drupalSettings']['gutenberg']['theme-support'] = $theme_support;
// Set available image sizes for editor.
$styles = ImageStyle::loadMultiple();
$sizes = [
[
'slug' => 'full',
'name' => t('Original'),
],
];
foreach ($styles as $style) {
$sizes[] = [
'slug' => $style
->getName(),
'name' => $style
->label(),
];
}
$form['#attached']['drupalSettings']['gutenberg']['image-sizes'] = $sizes;
$form['#attached']['drupalSettings']['gutenberg']['is-rtl'] = \Drupal::languageManager()
->getCurrentLanguage()
->getDirection() === LanguageInterface::DIRECTION_RTL;
$text_fields = UtilsController::getEntityTextFields($node);
$form['#attributes']['class'][] = 'metabox-base-form';
$form[$text_fields[0]]['widget'][0]['#format'] = 'gutenberg';
$form[$text_fields[0]]['#attributes']['class'][] = 'field--gutenberg';
// Hide the field label.
$form[$text_fields[0]]['widget'][0]['#title_display'] = 'hidden';
// Disable the summary field.
if (isset($form[$text_fields[0]]['widget'][0]['summary'])) {
$form[$text_fields[0]]['widget'][0]['summary']['#access'] = FALSE;
}
foreach ($text_fields as $fieldname) {
// For the rest of the text fields call after build to remove
// Gutenberg from text format options.
if ($text_fields[0] !== $fieldname) {
$form[$fieldname]['widget']['#after_build'][] = 'gutenberg_form_node_form_after_build';
}
}
// Let's move the remaining fields to a "special"
// form group that can be used later by JS to move to
// Gutenberg's sidebar.
$form['metabox_fields'] = [
'#type' => 'details',
'#access' => TRUE,
'#title' => t('More settings'),
'#weight' => 99,
// Group fallback in case JS fails to move to metaboxes.
'#group' => 'advanced',
];
// Some other module might have already init this container.
if (!isset($form['additional_fields'])) {
$form['additional_fields'] = [
'#type' => 'container',
'#title' => 'Additional',
'#weight' => -100,
];
}
// Move title to Published/meta pane.
$form['title']['#group'] = 'meta';
// Move status to Published/meta pane.
$form['status']['#group'] = 'meta';
// Move langcode to Published/meta pane.
if (isset($form['langcode'])) {
$form['langcode']['#group'] = 'meta';
}
$excluded_fields = [
'status',
'title',
'uid',
'created',
'changed',
'promote',
'sticky',
'path',
'comment',
'revision_log',
'langcode',
];
/*
* Rationale behind this "messy" algo:
* If there's any details fieldset on the form, add it to a special array
* and then, on the form after build, add its #id to a JS array.
* For any other type of fields, group them on the metabox_fields fieldset.
* This fieldset will also move to metaboxes area.
*/
$metabox_has_fields = FALSE;
$fields_with_details = [];
$field_names = UtilsController::getEntityFieldNames($node);
foreach ($field_names as $value) {
if (array_key_exists($value, $form) && $value !== $text_fields[0] && !in_array($value, $excluded_fields)) {
if (isset($form[$value]['widget']) && isset($form[$value]['widget'][0]) && isset($form[$value]['widget'][0]['#type']) && $form[$value]['widget'][0]['#type'] === 'details') {
$fields_with_details[] = $value;
}
else {
$form[$value]['#group'] = 'metabox_fields';
$metabox_has_fields = TRUE;
}
}
}
$form['#after_build'][] = 'gutenberg_form_node_form_details_after_build';
$form['#fields_with_details'] = $fields_with_details;
if (!$metabox_has_fields) {
unset($form['metabox_fields']);
}
// Is Bartik the default theme? Add some custom styles
// to look even better.
$default_theme = \Drupal::config('system.theme')
->get('default');
if ($default_theme === 'bartik') {
$form['#attached']['library'][] = 'gutenberg/bartik';
}
$theme = \Drupal::theme()
->getActiveTheme();
$theme_name = $theme
->getName();
// Check if current theme is Seven (admin)
if ($theme_name === 'seven') {
$form['#attached']['library'][] = 'gutenberg/seven';
}
// Check if current theme is Claro (admin)
if ($theme_name === 'claro') {
$form['#attached']['library'][] = 'gutenberg/claro';
}
$form['#attached']['drupalSettings']['gutenberg']['metaboxes'][] = 'edit-metabox-fields';
/** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
$module_handler = \Drupal::service('module_handler');
$form['#attached']['drupalSettings']['gutenberg']['media-enabled'] = $module_handler
->moduleExists('media');
if ($form['#attached']['drupalSettings']['gutenberg']['media-library-enabled'] = $module_handler
->moduleExists('media_library')) {
$form['#attached']['library'][] = 'media_library/ui';
}
}
/**
* Store messages in drupal settings.
*/
function gutenberg_handle_messages(&$form) {
$messages = \Drupal::messenger()
->deleteAll();
$form['#attached']['drupalSettings']['gutenberg']['messages'] = $messages;
}
/**
* Called by after build text fields on the form.
*/
function gutenberg_form_node_form_after_build(array $element, FormStateInterface $form_state) {
unset($element[0]['format']['format']['#options']['gutenberg']);
return $element;
}
/**
* Called by form after build.
*/
function gutenberg_form_node_form_details_after_build(array $element, FormStateInterface $form_state) {
// gutenberg_handle_messages($element);
foreach ($element['#fields_with_details'] as $value) {
$element['#attached']['drupalSettings']['gutenberg']['metaboxes'][] = $element[$value]['widget'][0]['#id'];
}
return $element;
}
/**
* Alter media form.
*/
function _gutenberg_media_form_alter(array &$form, FormStateInterface $form_state, string $form_id) {
$is_gutenberg = !is_null(\Drupal::request()->query
->get('gutenberg'));
if (!$is_gutenberg) {
return;
}
$form['actions']['delete']['#access'] = FALSE;
unset($form['actions']['delete']);
$form['#after_build'][] = 'gutenberg_form_media_edit_form_after_build';
$form['actions']['submit']['#submit'][] = 'gutenberg_form_media_edit_form_submit';
$form['actions']['submit']['#ajax'] = [
'callback' => 'gutenberg_form_media_edit_form_submit',
'event' => 'click',
];
$form['actions']['cancel'] = [
'#weight' => 99,
'#type' => 'button',
'#value' => t('Cancel'),
'#ajax' => [
'callback' => 'gutenberg_form_media_edit_form_cancel',
'event' => 'click',
],
];
$form['#submit'][] = 'gutenberg_form_media_edit_form_submit';
}
/**
* Alter media edit form submit.
*/
function gutenberg_form_media_edit_form_submit(array $form, FormStateInterface $form_state) {
$form_state
->disableRedirect();
$command = new CloseModalDialogCommand();
$response = new AjaxResponse();
$response
->addCommand($command);
return $response;
}
/**
* Alter media edit form cancel.
*/
function gutenberg_form_media_edit_form_cancel(array $form, FormStateInterface $form_state) {
$form_state
->disableRedirect();
$command = new CloseModalDialogCommand();
$response = new AjaxResponse();
$response
->addCommand($command);
return $response;
}
/**
* Alter media edit form.
*/
function gutenberg_form_media_edit_form_after_build(array $element, FormStateInterface $form_state) {
return $element;
}
/**
* Implements hook_entity_presave().
*/
function gutenberg_entity_presave($entity) {
if (!_gutenberg_is_gutenberg_enabled($entity)) {
// Leave early if Gutenberg is not enabled for this entity.
return;
}
/* @var $mapping_fields \Drupal\gutenberg\MappingFieldsHelper */
$mapping_fields = \Drupal::service('class_resolver')
->getInstanceFromDefinition(MappingFieldsHelper::class);
$mapping_fields
->setFieldMappingValues($entity);
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function gutenberg_theme_suggestions_node_edit_form_alter(array &$suggestions, array $variables) {
$config = \Drupal::service('config.factory')
->getEditable('gutenberg.settings');
$node = \Drupal::routeMatch()
->getParameter('node');
if (!$node) {
$route_match = \Drupal::service('current_route_match');
if (!$route_match
->getParameter('node_type')) {
return;
}
$node_type = $route_match
->getParameter('node_type')
->get('type');
}
else {
$node_type = $node->type
->getString();
}
$gutenberg_enabled = $config
->get($node_type . '_enable_full');
if (!$gutenberg_enabled) {
return;
}
$suggestions = [
'node_edit_form__gutenberg',
];
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function gutenberg_theme_suggestions_page_alter(array &$suggestions, array $variables) {
if (!in_array('page__node__edit', $suggestions) && !in_array('page__node__add', $suggestions)) {
return;
}
$config = \Drupal::service('config.factory')
->getEditable('gutenberg.settings');
$node = \Drupal::routeMatch()
->getParameter('node');
if (!$node) {
$route_match = \Drupal::service('current_route_match');
if (!$route_match
->getParameter('node_type')) {
return;
}
$node_type = $route_match
->getParameter('node_type')
->get('type');
}
else {
$node_type = $node->type
->getString();
}
$gutenberg_enabled = $config
->get($node_type . '_enable_full');
if ($gutenberg_enabled) {
if (in_array('page__node__edit', $suggestions)) {
$suggestions = [
'page__node__edit__gutenberg',
];
}
if (in_array('page__node__add', $suggestions)) {
$suggestions = [
'page__node__add__gutenberg',
];
}
}
}
/**
* Implements hook_element_info_alter().
*/
function gutenberg_element_info_alter(array &$info) {
if (!empty($info['text_format'])) {
// Add custom processor to eliminate the format if needed.
$info['text_format']['#process'][] = '_gutenberg_text_format_processor';
}
}
/**
* Process the text format element to eliminate the gutenberg format.
*
* On the fields that don't belong to content types with enabled gutenberg
* experience there is no need to have the gutenberg format.
*
* @param array $element
* Render Element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state object.
* @param array $complete_form
* Complete form array.
*
* @return array
* Processed render element.
*/
function _gutenberg_text_format_processor(array $element, FormStateInterface $form_state, array &$complete_form) {
// Check first if the format is in the list. It might be disabled or the
// current user has not rights to access it.
if (!empty($element['format']) && isset($element['format']['format']['#options']['gutenberg'])) {
// By default let's assume that gutenberg format is not allowed.
$gutenberg_allowed = FALSE;
/** @var \Drupal\Core\Entity\ContentEntityForm $form */
$form = $form_state
->getFormObject();
// Check whether the form that contains the element is an EntityForm.
if ($form instanceof EntityFormInterface) {
// Get the entity from the form object for further processing.
$entity = $form
->getEntity();
// Check whether entity is of node type, because currently only them are
// supported.
if ($entity instanceof NodeInterface) {
// Get the node type to get the Gutenberg experience setting.
$node_type = $entity
->bundle();
/** @var \Drupal\Core\Config\Config $config */
$config = \Drupal::service('config.factory')
->getEditable('gutenberg.settings');
$gutenberg_enabled = $config
->get($node_type . '_enable_full');
if (!empty($gutenberg_enabled)) {
// Gutenberg experience is enabled for current content type and
// the current user is allowed to use the format.
$gutenberg_allowed = TRUE;
}
}
}
// If Gutenberg experience is not enabled for the current form or
// current user is not allowed to use the format, disable the choice of
// Gutenberg format for this element.
if (!$gutenberg_allowed) {
unset($element['format']['format']['#options']['gutenberg']);
}
}
return $element;
}
/**
* Implements hook_views_pre_render().
*/
function gutenberg_views_pre_render(ViewExecutable $view) {
if ($view
->id() == "reusable_blocks" && $view->current_display == 'page_1') {
// Attached Gutenberg's basic style to reusable blocks view.
$view->element['#attached']['library'][] = 'gutenberg/admin';
$view->element['#attached']['library'][] = 'gutenberg/blocks-view';
}
}
/**
* Implements hook_page_attachments().
*/
function gutenberg_page_attachments(array &$page) {
/*
* FIXME: Recommending removing the generated CSS functionality since
* Gutenberg core doesn't support it, and causes the styles to be embedded
* on all pages, even those without Gutenberg on it.
* @see https://developer.wordpress.org/block-editor/developers/themes/theme-support/#block-color-palettes
* If the functionality is truly needed, it could be added as a third
* party/custom module.
*/
/** @var \Drupal\gutenberg\GutenbergLibraryManagerInterface $gutenberg_library_manager */
$gutenberg_library_manager = \Drupal::service('plugin.manager.gutenberg.library');
$theme_definition = $gutenberg_library_manager
->getActiveThemeMergedDefinition();
if (empty($theme_definition['theme-support']['colors']) || !empty($theme_definition['theme-includes-colors'])) {
// Color not available or the styles are already declared in the theme.
return;
}
$css_markup = '';
// Generate minified palette styles.
foreach ($theme_definition['theme-support']['colors'] as $color) {
$color_name = Html::getClass($color['name']);
$color_value = $color['color'];
$css_markup .= ":root .has-{$color_name}-color{color:{$color_value}}";
$css_markup .= ":root .has-{$color_name}-background-color{background-color:{$color_value}}";
}
$page['#attached']['html_head'][] = [
[
'#tag' => 'style',
'#attributes' => [
'id' => Html::getUniqueId('gutenberg-palette'),
],
'#value' => $css_markup,
],
'gutenberg_palette',
];
}
/**
* Implements hook_library_info_alter().
*/
function gutenberg_library_info_alter(&$libraries, $extension) {
if ($extension === 'gutenberg') {
$moduleHandler = \Drupal::moduleHandler();
$js_files_edit = [];
$css_files_edit = [];
$css_files_view = [];
$moduleHandler
->alter('gutenberg_blocks', $js_files_edit, $css_files_edit, $css_files_view);
foreach ($js_files_edit as $file) {
$libraries['blocks-edit']['js'][$file] = [];
}
foreach ($css_files_edit as $file) {
$libraries['blocks-edit']['css']['base'][$file] = [];
}
foreach ($css_files_view as $file) {
$libraries['blocks-edit']['css']['base'][$file] = [];
$libraries['blocks-view']['css']['base'][$file] = [];
}
}
}
/**
* Implements hook_help().
*/
function gutenberg_help($route_name, RouteMatchInterface $route_match) {
if ($route_name === 'help.page.gutenberg') {
$readme_file = file_exists(__DIR__ . '/README.md') ? __DIR__ . '/README.md' : __DIR__ . '/README.txt';
if (!file_exists($readme_file)) {
return NULL;
}
$text = file_get_contents($readme_file);
if (!\Drupal::moduleHandler()
->moduleExists('markdown')) {
return '<pre>' . $text . '</pre>';
}
else {
// Use the Markdown filter to render the README.
$filter_manager = \Drupal::service('plugin.manager.filter');
$settings = \Drupal::configFactory()
->get('markdown.settings')
->getRawData();
$config = [
'settings' => $settings,
];
$filter = $filter_manager
->createInstance('markdown', $config);
return $filter
->process($text, 'en');
}
}
return NULL;
}
/**
* Implements hook_themes_installed().
*/
function gutenberg_themes_installed($theme_list) {
\Drupal::service('plugin.manager.gutenberg.library')
->clearCachedDefinitions();
}
/**
* Implements hook_themes_uninstalled().
*/
function gutenberg_themes_uninstalled(array $themes) {
\Drupal::service('plugin.manager.gutenberg.library')
->clearCachedDefinitions();
}
/**
* Checks whether Gutenberg is enabled for an entity.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to check.
*
* @return bool
* Whether the entity is supported.
*/
function _gutenberg_is_gutenberg_enabled(EntityInterface $entity = NULL) {
if (!$entity) {
return FALSE;
}
if ($entity
->getEntityTypeId() !== 'node') {
return FALSE;
}
/*
* TODO read from the entity type's third_party_settings instead of a global.
* @see menu_ui_form_node_form_alter()
* and https://www.sitepoint.com/drupal-8-third-party-settings-and-pseudo-fields/
*/
$config = \Drupal::service('config.factory')
->get('gutenberg.settings');
$node_type = $entity
->bundle();
return (bool) $config
->get($node_type . '_enable_full');
}
Functions
Constants
Name | Description |
---|---|
GUTENBERG_JS_GIT_COMMIT | |
GUTENBERG_JS_VERSION |