Conditionally Preventing Node Deletion in Drupal
October 23, 2014

Introduction

To prevent your Drupal 7 website editors from deleting content, under certain conditions, is not that difficult if you know the proper Drupal hooks to use. However, finding those hooks isn't easy and we're sharing this blog post with you in the hope that it will save you a few programming headaches.

What are Drupal Hooks?

If you're a Drupal beginner wondering what hooks are, don't fret, and check out this excellent post on Drupal Answers with a really neat explanation of the basic concept behind Drupal hooks.

How to Implement Drupal Hooks?

Drupal hooks are implemented inside custom modules. Check out this decent guide to writing your first module in Drupal 7 that we have just finished writing.

Why Prevent Content Deletion?

Let's say you're using Entity Reference and you have referenced nodes from the current node a user is trying to delete. The deletion of this node might leave your website in an invalid state.

Another example would be if you're using a standard Drupal menu, like the default main menu, in your website and the node to be deleted has sub menu items and you don't want to mess up with the menu's hierarchy, especially if you're using pathauto to generate your URLs based on the menu's tree structure.

Building a solid Drupal website requires adaptation to your client's business requirements and implementing extra features and performing extra checks on top of Drupal's standard ones is a strong step in this direction.

Next, we explore the code you can use to disable access to the deletion of a Drupal node.

 

Screenshot showing node deletion prevention in Drupal

Screenshot showing node deletion prevention in Drupal

 

The Code

This function was written and tested in Drupal 7 using hooks inside a custom module. Its purpose it to check whether the current node has child menu items and then prevent deletion of this node and also show a message explaining the situation.

We use a function from our previous blog post to get all menu children of this current node path.

Read the comments in the function below for more info. In addition, check out the documentation of hook_form_FORM_ID_alter as it's your window to modifying a lot of the Drupal forms presented in the admin area. All you have to do is get the form's id from the admin backend, using Firebug for example, and modify the hook's function name accordingly to modify the form you need. Our function's name below serves as an example.

Modify and tinker according to your needs.

Happy coding.

 


<?php

/**
 * Implements hook_form_FORM_ID_alter() to conditionally prevent node deletion.
 * 
 * We check if the current node has child menu items and, if yes, we prevent
 * this node's deletion and also show a message explaining the situation and 
 * links to the child nodes so that the user can easily delete them first
 * or move them to another parent menu item.
 * 
 * This can be useful in many cases especially if you count on the paths of 
 * the child items being derived from their parent item path, for example.
 */
function sk_form_node_delete_confirm_alter(&$form, $form_state) {
    //Check if we have a node id and stop if not
    if(empty($form['nid']['#value'])) {
        return;
    }
    
    //Load the node from the form
    $node = node_load($form['nid']['#value']);
    
    //Check if node properly loaded and stop if not
    //Empty checks for both $node being not empty and also for its property nid
    if(empty($node->nid)) {
        return;
    }
    
    //Get child menu items array for this node
    $children_nids = sk_get_all_menu_node_children_ids('node/' . $node->nid);
    $children_count = count($children_nids);
    
    //If we have children, do set a warning and disable delete button and such
    //so that this node cannot be deleted by the user.
    //Note: we are not 100% that this prevents the user from deleting it through
    //views bulk operations for example or by faking a post request, but for our
    //needs, this is adequate as we trust the editors on our websites.
    if(!empty($children_nids)) {
        //Construct explanatory message
        $msg = '';
        
        $t1 = '';
        $t1 .= '%title is part of a menu and has %count child menu items. ';
        $t1 .= 'If you delete it, the URL paths of its children will no longer work.';
        $msg .= '<p>';
        $msg .= t($t1, array('%title' => $node->title, '%count' => $children_count));
        $msg .= '</p>';
        
        $t2 = 'Please check the %count child menu items below and delete them first.';
        $msg .= '<p>';
        $msg .= t($t2, array('%count' => $children_count));
        $msg .= '</p>';
        
        $msg .= '<ol>';        
        $children_nodes = node_load_multiple($children_nids);
        if(!empty($children_nodes)) {
            foreach($children_nodes as $child_node) {
                if(!empty($child_node->nid)) {
                    $msg .= '<li>';
                    $msg .= '<a href="' . url('node/' . $child_node->nid) . '">';
                    $msg .= $child_node->title;
                    $msg .= '</a>';
                    $msg .= '</li>';
                }
            }
        }
        $msg .= '</ol>';
        
        //Set explanatory message
        $form['sk_children_exist_warning'] = array(
            '#markup' => $msg,
            '#weight' => -10,
        );

        //Remove the 'This action cannot be undone' message
        unset($form['description']);

        //Remove the delete button
        unset($form['actions']['submit']);
    }
}


Drupal Development Open Source

Share this post


Written by
Mario Awad

Founder of SOFTKUBE, lead developer, and getting things done addict. Passionate about open source, user interface design, business development, and the tech world.

More about Mario Awad


About
SOFTKUBE

A small team of experts developing simple, usable, and high-quality web solutions. We blog about business, entrepreneurship, web development, and technology.

More about us


Recent Posts

Custom Theme Migration from Drupal 9 to Drupal 10

How to Change the Most Recent Git Commit Message

How to Make Google Chrome Forget a Permanent HTTP 301 Redirect

Finding and Fixing Unintended Body Overflow to Remove Horizontal Scrollbars

View all posts


All Posts Categories

Business Cheat Sheets CLI Design Development Downloads Drupal Email Google Apps HID Keyboards Multilingualism Open Source Philosophy PHP Pointing Devices Productivity Quotes Science Security SEO Technology Thoughts Windows Zend Framework