Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /**
|
Chris@0
|
4 * @file
|
Chris@0
|
5 * Contains content_moderation.module.
|
Chris@0
|
6 */
|
Chris@0
|
7
|
Chris@0
|
8 use Drupal\content_moderation\EntityOperations;
|
Chris@0
|
9 use Drupal\content_moderation\EntityTypeInfo;
|
Chris@0
|
10 use Drupal\content_moderation\ContentPreprocess;
|
Chris@14
|
11 use Drupal\content_moderation\Plugin\Action\ModerationOptOutPublish;
|
Chris@14
|
12 use Drupal\content_moderation\Plugin\Action\ModerationOptOutUnpublish;
|
Chris@0
|
13 use Drupal\Core\Access\AccessResult;
|
Chris@18
|
14 use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
|
Chris@0
|
15 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
|
Chris@0
|
16 use Drupal\Core\Entity\EntityInterface;
|
Chris@0
|
17 use Drupal\Core\Entity\EntityPublishedInterface;
|
Chris@0
|
18 use Drupal\Core\Entity\EntityTypeInterface;
|
Chris@0
|
19 use Drupal\Core\Field\FieldDefinitionInterface;
|
Chris@0
|
20 use Drupal\Core\Field\FieldItemListInterface;
|
Chris@0
|
21 use Drupal\Core\Form\FormStateInterface;
|
Chris@0
|
22 use Drupal\Core\Routing\RouteMatchInterface;
|
Chris@0
|
23 use Drupal\Core\Session\AccountInterface;
|
Chris@14
|
24 use Drupal\Core\Url;
|
Chris@18
|
25 use Drupal\views\Plugin\views\filter\Broken;
|
Chris@18
|
26 use Drupal\views\ViewExecutable;
|
Chris@18
|
27 use Drupal\views\Views;
|
Chris@0
|
28 use Drupal\workflows\WorkflowInterface;
|
Chris@14
|
29 use Drupal\Core\Action\Plugin\Action\PublishAction;
|
Chris@14
|
30 use Drupal\Core\Action\Plugin\Action\UnpublishAction;
|
Chris@0
|
31 use Drupal\workflows\Entity\Workflow;
|
Chris@14
|
32 use Drupal\views\Entity\View;
|
Chris@0
|
33
|
Chris@0
|
34 /**
|
Chris@0
|
35 * Implements hook_help().
|
Chris@0
|
36 */
|
Chris@0
|
37 function content_moderation_help($route_name, RouteMatchInterface $route_match) {
|
Chris@0
|
38 switch ($route_name) {
|
Chris@0
|
39 // Main module help for the content_moderation module.
|
Chris@0
|
40 case 'help.page.content_moderation':
|
Chris@0
|
41 $output = '';
|
Chris@0
|
42 $output .= '<h3>' . t('About') . '</h3>';
|
Chris@14
|
43 $output .= '<p>' . t('The Content Moderation module allows you to expand on Drupal\'s "unpublished" and "published" states for content. It allows you to have a published version that is live, but have a separate working copy that is undergoing review before it is published. This is achieved by using <a href=":workflows">Workflows</a> to apply different states and transitions to entities as needed. For more information, see the <a href=":content_moderation">online documentation for the Content Moderation module</a>.', [':content_moderation' => 'https://www.drupal.org/documentation/modules/content_moderation', ':workflows' => Url::fromRoute('help.page', ['name' => 'workflows'])->toString()]) . '</p>';
|
Chris@0
|
44 $output .= '<h3>' . t('Uses') . '</h3>';
|
Chris@0
|
45 $output .= '<dl>';
|
Chris@14
|
46 $output .= '<dt>' . t('Applying workflows') . '</dt>';
|
Chris@14
|
47 $output .= '<dd>' . t('Content Moderation allows you to apply <a href=":workflows">Workflows</a> to content, custom blocks, and other <a href=":field_help" title="Field module help, with background on content entities">content entities</a>, to provide more fine-grained publishing options. For example, a Basic page might have states such as Draft and Published, with allowed transitions such as Draft to Published (making the current revision "live"), and Published to Draft (making a new draft revision of published content).', [':workflows' => Url::fromRoute('help.page', ['name' => 'workflows'])->toString(), ':field_help' => Url::fromRoute('help.page', ['name' => 'field'])->toString()]) . '</dd>';
|
Chris@14
|
48 if (\Drupal::moduleHandler()->moduleExists('views')) {
|
Chris@14
|
49 $moderated_content_view = View::load('moderated_content');
|
Chris@14
|
50 if (isset($moderated_content_view) && $moderated_content_view->status() === TRUE) {
|
Chris@14
|
51 $output .= '<dt>' . t('Moderating content') . '</dt>';
|
Chris@14
|
52 $output .= '<dd>' . t('You can view a list of content awaiting moderation on the <a href=":moderated">moderated content page</a>. This will show any content in an unpublished state, such as Draft or Archived, to help surface content that requires more work from content editors.', [':moderated' => Url::fromRoute('view.moderated_content.moderated_content')->toString()]) . '</dd>';
|
Chris@14
|
53 }
|
Chris@14
|
54 }
|
Chris@0
|
55 $output .= '<dt>' . t('Configure Content Moderation permissions') . '</dt>';
|
Chris@14
|
56 $output .= '<dd>' . t('Each transition is exposed as a permission. If a user has the permission for a transition, they can use the transition to change the state of the content item, from Draft to Published.') . '</dd>';
|
Chris@0
|
57 $output .= '</dl>';
|
Chris@0
|
58 return $output;
|
Chris@0
|
59 }
|
Chris@0
|
60 }
|
Chris@0
|
61
|
Chris@0
|
62 /**
|
Chris@0
|
63 * Implements hook_entity_base_field_info().
|
Chris@0
|
64 */
|
Chris@0
|
65 function content_moderation_entity_base_field_info(EntityTypeInterface $entity_type) {
|
Chris@0
|
66 return \Drupal::service('class_resolver')
|
Chris@0
|
67 ->getInstanceFromDefinition(EntityTypeInfo::class)
|
Chris@0
|
68 ->entityBaseFieldInfo($entity_type);
|
Chris@0
|
69 }
|
Chris@0
|
70
|
Chris@0
|
71 /**
|
Chris@18
|
72 * Implements hook_entity_bundle_field_info().
|
Chris@18
|
73 */
|
Chris@18
|
74 function content_moderation_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
|
Chris@18
|
75 if (isset($base_field_definitions['moderation_state'])) {
|
Chris@18
|
76 // Add the target bundle to the moderation state field. Since each bundle
|
Chris@18
|
77 // can be attached to a different moderation workflow, adding this
|
Chris@18
|
78 // information to the field definition allows the associated workflow to be
|
Chris@18
|
79 // derived where a field definition is present.
|
Chris@18
|
80 $base_field_definitions['moderation_state']->setTargetBundle($bundle);
|
Chris@18
|
81 return [
|
Chris@18
|
82 'moderation_state' => $base_field_definitions['moderation_state'],
|
Chris@18
|
83 ];
|
Chris@18
|
84 }
|
Chris@18
|
85 }
|
Chris@18
|
86
|
Chris@18
|
87 /**
|
Chris@0
|
88 * Implements hook_entity_type_alter().
|
Chris@0
|
89 */
|
Chris@0
|
90 function content_moderation_entity_type_alter(array &$entity_types) {
|
Chris@0
|
91 \Drupal::service('class_resolver')
|
Chris@0
|
92 ->getInstanceFromDefinition(EntityTypeInfo::class)
|
Chris@0
|
93 ->entityTypeAlter($entity_types);
|
Chris@0
|
94 }
|
Chris@0
|
95
|
Chris@0
|
96 /**
|
Chris@0
|
97 * Implements hook_entity_presave().
|
Chris@0
|
98 */
|
Chris@0
|
99 function content_moderation_entity_presave(EntityInterface $entity) {
|
Chris@0
|
100 return \Drupal::service('class_resolver')
|
Chris@0
|
101 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
102 ->entityPresave($entity);
|
Chris@0
|
103 }
|
Chris@0
|
104
|
Chris@0
|
105 /**
|
Chris@0
|
106 * Implements hook_entity_insert().
|
Chris@0
|
107 */
|
Chris@0
|
108 function content_moderation_entity_insert(EntityInterface $entity) {
|
Chris@0
|
109 return \Drupal::service('class_resolver')
|
Chris@0
|
110 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
111 ->entityInsert($entity);
|
Chris@0
|
112 }
|
Chris@0
|
113
|
Chris@0
|
114 /**
|
Chris@0
|
115 * Implements hook_entity_update().
|
Chris@0
|
116 */
|
Chris@0
|
117 function content_moderation_entity_update(EntityInterface $entity) {
|
Chris@0
|
118 return \Drupal::service('class_resolver')
|
Chris@0
|
119 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
120 ->entityUpdate($entity);
|
Chris@0
|
121 }
|
Chris@0
|
122
|
Chris@0
|
123 /**
|
Chris@0
|
124 * Implements hook_entity_delete().
|
Chris@0
|
125 */
|
Chris@0
|
126 function content_moderation_entity_delete(EntityInterface $entity) {
|
Chris@0
|
127 return \Drupal::service('class_resolver')
|
Chris@0
|
128 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
129 ->entityDelete($entity);
|
Chris@0
|
130 }
|
Chris@0
|
131
|
Chris@0
|
132 /**
|
Chris@0
|
133 * Implements hook_entity_revision_delete().
|
Chris@0
|
134 */
|
Chris@0
|
135 function content_moderation_entity_revision_delete(EntityInterface $entity) {
|
Chris@0
|
136 return \Drupal::service('class_resolver')
|
Chris@0
|
137 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
138 ->entityRevisionDelete($entity);
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 /**
|
Chris@0
|
142 * Implements hook_entity_translation_delete().
|
Chris@0
|
143 */
|
Chris@0
|
144 function content_moderation_entity_translation_delete(EntityInterface $translation) {
|
Chris@0
|
145 return \Drupal::service('class_resolver')
|
Chris@0
|
146 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
147 ->entityTranslationDelete($translation);
|
Chris@0
|
148 }
|
Chris@0
|
149
|
Chris@0
|
150 /**
|
Chris@14
|
151 * Implements hook_entity_prepare_form().
|
Chris@14
|
152 */
|
Chris@14
|
153 function content_moderation_entity_prepare_form(EntityInterface $entity, $operation, FormStateInterface $form_state) {
|
Chris@14
|
154 \Drupal::service('class_resolver')
|
Chris@14
|
155 ->getInstanceFromDefinition(EntityTypeInfo::class)
|
Chris@14
|
156 ->entityPrepareForm($entity, $operation, $form_state);
|
Chris@14
|
157 }
|
Chris@14
|
158
|
Chris@14
|
159 /**
|
Chris@0
|
160 * Implements hook_form_alter().
|
Chris@0
|
161 */
|
Chris@0
|
162 function content_moderation_form_alter(&$form, FormStateInterface $form_state, $form_id) {
|
Chris@0
|
163 \Drupal::service('class_resolver')
|
Chris@0
|
164 ->getInstanceFromDefinition(EntityTypeInfo::class)
|
Chris@0
|
165 ->formAlter($form, $form_state, $form_id);
|
Chris@0
|
166 }
|
Chris@0
|
167
|
Chris@0
|
168 /**
|
Chris@0
|
169 * Implements hook_preprocess_HOOK().
|
Chris@0
|
170 */
|
Chris@0
|
171 function content_moderation_preprocess_node(&$variables) {
|
Chris@0
|
172 \Drupal::service('class_resolver')
|
Chris@0
|
173 ->getInstanceFromDefinition(ContentPreprocess::class)
|
Chris@0
|
174 ->preprocessNode($variables);
|
Chris@0
|
175 }
|
Chris@0
|
176
|
Chris@0
|
177 /**
|
Chris@0
|
178 * Implements hook_entity_extra_field_info().
|
Chris@0
|
179 */
|
Chris@0
|
180 function content_moderation_entity_extra_field_info() {
|
Chris@0
|
181 return \Drupal::service('class_resolver')
|
Chris@0
|
182 ->getInstanceFromDefinition(EntityTypeInfo::class)
|
Chris@0
|
183 ->entityExtraFieldInfo();
|
Chris@0
|
184 }
|
Chris@0
|
185
|
Chris@0
|
186 /**
|
Chris@0
|
187 * Implements hook_entity_view().
|
Chris@0
|
188 */
|
Chris@0
|
189 function content_moderation_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
|
Chris@0
|
190 \Drupal::service('class_resolver')
|
Chris@0
|
191 ->getInstanceFromDefinition(EntityOperations::class)
|
Chris@0
|
192 ->entityView($build, $entity, $display, $view_mode);
|
Chris@0
|
193 }
|
Chris@0
|
194
|
Chris@0
|
195 /**
|
Chris@18
|
196 * Implements hook_entity_form_display_alter().
|
Chris@18
|
197 */
|
Chris@18
|
198 function content_moderation_entity_form_display_alter(EntityFormDisplayInterface $form_display, array $context) {
|
Chris@18
|
199 if ($context['form_mode'] === 'layout_builder') {
|
Chris@18
|
200 $form_display->setComponent('moderation_state', [
|
Chris@18
|
201 'type' => 'moderation_state_default',
|
Chris@18
|
202 'weight' => -900,
|
Chris@18
|
203 'settings' => [],
|
Chris@18
|
204 ]);
|
Chris@18
|
205 }
|
Chris@18
|
206 }
|
Chris@18
|
207
|
Chris@18
|
208 /**
|
Chris@0
|
209 * Implements hook_entity_access().
|
Chris@0
|
210 *
|
Chris@0
|
211 * Entities should be viewable if unpublished and the user has the appropriate
|
Chris@0
|
212 * permission. This permission is therefore effectively mandatory for any user
|
Chris@0
|
213 * that wants to moderate things.
|
Chris@0
|
214 */
|
Chris@0
|
215 function content_moderation_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
Chris@0
|
216 /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
|
Chris@0
|
217 $moderation_info = Drupal::service('content_moderation.moderation_information');
|
Chris@0
|
218
|
Chris@0
|
219 $access_result = NULL;
|
Chris@0
|
220 if ($operation === 'view') {
|
Chris@0
|
221 $access_result = (($entity instanceof EntityPublishedInterface) && !$entity->isPublished())
|
Chris@0
|
222 ? AccessResult::allowedIfHasPermission($account, 'view any unpublished content')
|
Chris@0
|
223 : AccessResult::neutral();
|
Chris@0
|
224
|
Chris@0
|
225 $access_result->addCacheableDependency($entity);
|
Chris@0
|
226 }
|
Chris@0
|
227 elseif ($operation === 'update' && $moderation_info->isModeratedEntity($entity) && $entity->moderation_state) {
|
Chris@0
|
228 /** @var \Drupal\content_moderation\StateTransitionValidation $transition_validation */
|
Chris@0
|
229 $transition_validation = \Drupal::service('content_moderation.state_transition_validation');
|
Chris@0
|
230
|
Chris@0
|
231 $valid_transition_targets = $transition_validation->getValidTransitions($entity, $account);
|
Chris@17
|
232 $access_result = $valid_transition_targets ? AccessResult::neutral() : AccessResult::forbidden('No valid transitions exist for given account.');
|
Chris@0
|
233
|
Chris@0
|
234 $access_result->addCacheableDependency($entity);
|
Chris@0
|
235 $access_result->addCacheableDependency($account);
|
Chris@0
|
236 $workflow = $moderation_info->getWorkflowForEntity($entity);
|
Chris@0
|
237 $access_result->addCacheableDependency($workflow);
|
Chris@0
|
238 foreach ($valid_transition_targets as $valid_transition_target) {
|
Chris@0
|
239 $access_result->addCacheableDependency($valid_transition_target);
|
Chris@0
|
240 }
|
Chris@0
|
241 }
|
Chris@0
|
242
|
Chris@18
|
243 // Do not allow users to delete the state that is configured as the default
|
Chris@18
|
244 // state for the workflow.
|
Chris@18
|
245 if ($entity instanceof WorkflowInterface) {
|
Chris@18
|
246 $configuration = $entity->getTypePlugin()->getConfiguration();
|
Chris@18
|
247 if (!empty($configuration['default_moderation_state']) && $operation === sprintf('delete-state:%s', $configuration['default_moderation_state'])) {
|
Chris@18
|
248 return AccessResult::forbidden()->addCacheableDependency($entity);
|
Chris@18
|
249 }
|
Chris@18
|
250 }
|
Chris@18
|
251
|
Chris@0
|
252 return $access_result;
|
Chris@0
|
253 }
|
Chris@0
|
254
|
Chris@0
|
255 /**
|
Chris@0
|
256 * Implements hook_entity_field_access().
|
Chris@0
|
257 */
|
Chris@0
|
258 function content_moderation_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
|
Chris@0
|
259 if ($items && $operation === 'edit') {
|
Chris@0
|
260 /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
|
Chris@0
|
261 $moderation_info = Drupal::service('content_moderation.moderation_information');
|
Chris@0
|
262
|
Chris@0
|
263 $entity_type = \Drupal::entityTypeManager()->getDefinition($field_definition->getTargetEntityTypeId());
|
Chris@0
|
264
|
Chris@0
|
265 $entity = $items->getEntity();
|
Chris@0
|
266
|
Chris@0
|
267 // Deny edit access to the published field if the entity is being moderated.
|
Chris@0
|
268 if ($entity_type->hasKey('published') && $moderation_info->isModeratedEntity($entity) && $entity->moderation_state && $field_definition->getName() == $entity_type->getKey('published')) {
|
Chris@17
|
269 return AccessResult::forbidden('Cannot edit the published field of moderated entities.');
|
Chris@0
|
270 }
|
Chris@0
|
271 }
|
Chris@0
|
272
|
Chris@0
|
273 return AccessResult::neutral();
|
Chris@0
|
274 }
|
Chris@0
|
275
|
Chris@0
|
276 /**
|
Chris@0
|
277 * Implements hook_theme().
|
Chris@0
|
278 */
|
Chris@0
|
279 function content_moderation_theme() {
|
Chris@0
|
280 return ['entity_moderation_form' => ['render element' => 'form']];
|
Chris@0
|
281 }
|
Chris@0
|
282
|
Chris@0
|
283 /**
|
Chris@0
|
284 * Implements hook_action_info_alter().
|
Chris@0
|
285 */
|
Chris@0
|
286 function content_moderation_action_info_alter(&$definitions) {
|
Chris@0
|
287
|
Chris@0
|
288 // The publish/unpublish actions are not valid on moderated entities. So swap
|
Chris@0
|
289 // their implementations out for alternates that will become a no-op on a
|
Chris@14
|
290 // moderated entity. If another module has already swapped out those classes,
|
Chris@0
|
291 // though, we'll be polite and do nothing.
|
Chris@14
|
292 foreach ($definitions as &$definition) {
|
Chris@14
|
293 if ($definition['id'] === 'entity:publish_action' && $definition['class'] == PublishAction::class) {
|
Chris@14
|
294 $definition['class'] = ModerationOptOutPublish::class;
|
Chris@14
|
295 }
|
Chris@14
|
296 if ($definition['id'] === 'entity:unpublish_action' && $definition['class'] == UnpublishAction::class) {
|
Chris@14
|
297 $definition['class'] = ModerationOptOutUnpublish::class;
|
Chris@14
|
298 }
|
Chris@0
|
299 }
|
Chris@0
|
300 }
|
Chris@0
|
301
|
Chris@0
|
302 /**
|
Chris@0
|
303 * Implements hook_entity_bundle_info_alter().
|
Chris@0
|
304 */
|
Chris@0
|
305 function content_moderation_entity_bundle_info_alter(&$bundles) {
|
Chris@14
|
306 $translatable = FALSE;
|
Chris@0
|
307 /** @var \Drupal\workflows\WorkflowInterface $workflow */
|
Chris@0
|
308 foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
|
Chris@0
|
309 /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration $plugin */
|
Chris@0
|
310 $plugin = $workflow->getTypePlugin();
|
Chris@0
|
311 foreach ($plugin->getEntityTypes() as $entity_type_id) {
|
Chris@0
|
312 foreach ($plugin->getBundlesForEntityType($entity_type_id) as $bundle_id) {
|
Chris@0
|
313 if (isset($bundles[$entity_type_id][$bundle_id])) {
|
Chris@0
|
314 $bundles[$entity_type_id][$bundle_id]['workflow'] = $workflow->id();
|
Chris@14
|
315 // If we have even one moderation-enabled translatable bundle, we need
|
Chris@14
|
316 // to make the moderation state bundle translatable as well, to enable
|
Chris@14
|
317 // the revision translation merge logic also for content moderation
|
Chris@14
|
318 // state revisions.
|
Chris@14
|
319 if (!empty($bundles[$entity_type_id][$bundle_id]['translatable'])) {
|
Chris@14
|
320 $translatable = TRUE;
|
Chris@14
|
321 }
|
Chris@0
|
322 }
|
Chris@0
|
323 }
|
Chris@0
|
324 }
|
Chris@0
|
325 }
|
Chris@14
|
326 $bundles['content_moderation_state']['content_moderation_state']['translatable'] = $translatable;
|
Chris@0
|
327 }
|
Chris@0
|
328
|
Chris@0
|
329 /**
|
Chris@0
|
330 * Implements hook_entity_bundle_delete().
|
Chris@0
|
331 */
|
Chris@0
|
332 function content_moderation_entity_bundle_delete($entity_type_id, $bundle_id) {
|
Chris@0
|
333 // Remove non-configuration based bundles from content moderation based
|
Chris@0
|
334 // workflows when they are removed.
|
Chris@0
|
335 foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
|
Chris@0
|
336 if ($workflow->getTypePlugin()->appliesToEntityTypeAndBundle($entity_type_id, $bundle_id)) {
|
Chris@0
|
337 $workflow->getTypePlugin()->removeEntityTypeAndBundle($entity_type_id, $bundle_id);
|
Chris@0
|
338 $workflow->save();
|
Chris@0
|
339 }
|
Chris@0
|
340 }
|
Chris@0
|
341 }
|
Chris@0
|
342
|
Chris@0
|
343 /**
|
Chris@0
|
344 * Implements hook_ENTITY_TYPE_insert().
|
Chris@0
|
345 */
|
Chris@0
|
346 function content_moderation_workflow_insert(WorkflowInterface $entity) {
|
Chris@0
|
347 // Clear bundle cache so workflow gets added or removed from the bundle
|
Chris@0
|
348 // information.
|
Chris@0
|
349 \Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
Chris@0
|
350 // Clear field cache so extra field is added or removed.
|
Chris@0
|
351 \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
Chris@18
|
352 // Clear the views data cache so the extra field is available in views.
|
Chris@18
|
353 if (\Drupal::moduleHandler()->moduleExists('views')) {
|
Chris@18
|
354 Views::viewsData()->clear();
|
Chris@18
|
355 }
|
Chris@0
|
356 }
|
Chris@0
|
357
|
Chris@0
|
358 /**
|
Chris@0
|
359 * Implements hook_ENTITY_TYPE_update().
|
Chris@0
|
360 */
|
Chris@0
|
361 function content_moderation_workflow_update(WorkflowInterface $entity) {
|
Chris@0
|
362 // Clear bundle cache so workflow gets added or removed from the bundle
|
Chris@0
|
363 // information.
|
Chris@0
|
364 \Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
Chris@0
|
365 // Clear field cache so extra field is added or removed.
|
Chris@0
|
366 \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
Chris@18
|
367 // Clear the views data cache so the extra field is available in views.
|
Chris@18
|
368 if (\Drupal::moduleHandler()->moduleExists('views')) {
|
Chris@18
|
369 Views::viewsData()->clear();
|
Chris@18
|
370 }
|
Chris@0
|
371 }
|
Chris@18
|
372
|
Chris@18
|
373 /**
|
Chris@18
|
374 * Implements hook_views_post_execute().
|
Chris@18
|
375 */
|
Chris@18
|
376 function content_moderation_views_post_execute(ViewExecutable $view) {
|
Chris@18
|
377 // @todo, remove this once broken handlers in views configuration result in
|
Chris@18
|
378 // a view no longer returning results. https://www.drupal.org/node/2907954.
|
Chris@18
|
379 foreach ($view->filter as $id => $filter) {
|
Chris@18
|
380 if (strpos($id, 'moderation_state') === 0 && $filter instanceof Broken) {
|
Chris@18
|
381 $view->result = [];
|
Chris@18
|
382 break;
|
Chris@18
|
383 }
|
Chris@18
|
384 }
|
Chris@18
|
385 }
|