Quickly Protecting a Few Nodes from Deletion in Drupal 8
I’m working on a Drupal 8 site with some critical pages for which we do not want to allow deletion. The homepage, for example, is a basic page; we do not want to allow anyone (even UID #1) to delete this page. If there comes a time where UID #1 decides they need to, they’ll have to update this simple code to support that. We need not make it any more complicated than that for this particular project.
Here’s a solution that:
- shows nothing but an error on the “Delete” form for specific nodes (works for all users)
- prevents deletion by any means (works for all users except UID #1)
- why except UID #1? because hook_node_access doesn’t run for this user
Note that the array of node IDs has labels to help the developer know which node ID represents which page. There are only three nodes and this only happens on deletion or deletion form rendering, so performance is a non-issue. array_search() will work just fine.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<?php use Drupal\Core\Access\AccessResult; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountInterface; use Drupal\node\NodeInterface; /** * Returns TRUE if node should be delete-protected. * * @param \Drupal\node\NodeInterface $node * Node to check. * * @return bool * TRUE if node should be delete-protected. */ function mymodule_node_should_be_delete_protected(NodeInterface $node) { $deny_deletion_pages = [ 'home' => 1, 'discussion_groups' => 10, 'learn' => 22, ]; if (array_search($node->id(), $deny_deletion_pages) !== FALSE) { return TRUE; } return FALSE; } /** * Implements hook_node_access(). */ function mymodule_node_access(NodeInterface $node, $op, AccountInterface $account) { if ($op == 'delete') { if (mymodule_node_should_be_delete_protected($node)) { return AccessResult::forbidden(); } } return AccessResult::neutral(); } /** * Implements hook_form_FORM_ID_alter(). * * Prevents deletion of specific pages. */ function mymodule_form_node_page_delete_form_alter(&$form, FormStateInterface $form_state) { $node = \Drupal::routeMatch()->getParameter('node'); if (!$node instanceof NodeInterface) { return; } if (mymodule_node_should_be_delete_protected($node)) { $form['description']['#access'] = FALSE; $form['actions']['cancel']['#access'] = FALSE; $form['actions']['submit']['#access'] = FALSE; \Drupal::messenger()->addError( t('@title is a system page; you cannot delete this page.', [ '@title' => $node->getTitle(), ])); } } |