Create An Action On 'node_insert' Or 'node_presave'

by ADMIN 52 views

Creating dynamic and interactive websites often involves automating tasks when specific events occur. In Drupal, these events are called hooks, and the automated tasks are called actions. Two crucial hooks for content management are node_insert and node_presave. This article explores how to create actions triggered by these hooks, focusing on practical examples and common challenges.

Understanding node_insert and node_presave Hooks

Before diving into creating actions, it's essential to understand the difference between node_insert and node_presave. Both hooks relate to node creation and updates, but they fire at different stages of the process.

  • node_presave: This hook is invoked before a node is saved to the database. It provides an opportunity to modify the node object before it's written to the database. Common use cases include data validation, altering field values, and setting default values based on other fields.
  • node_insert: This hook is invoked after a new node has been successfully saved to the database. It's ideal for tasks that depend on the node having a unique ID, such as sending notifications, creating related content, or updating external systems.

The choice between these hooks depends on the specific requirements of your action. If you need to modify the node's data before it's saved, node_presave is the hook to use. If you need to perform actions after the node is saved, such as sending an email notification or updating an external system, node_insert is more appropriate.

Creating a Custom Action

To create a custom action in Drupal, you'll typically need to write a custom module. Here's a step-by-step guide to creating an action triggered by node_insert or node_presave:

Step 1: Set Up Your Module

  1. Create a new directory in the modules/custom directory of your Drupal installation. Name it something descriptive, like my_custom_actions.
  2. Inside your module directory, create two files:
    • my_custom_actions.info.yml: This file contains metadata about your module, such as its name, description, and dependencies.
    • my_custom_actions.module: This file contains the PHP code for your module, including the action definition and the hook implementation.

Step 2: Define the Module Information

In your my_custom_actions.info.yml file, add the following information:

name: My Custom Actions
type: module
description: Provides custom actions triggered by node events.
core_version_requirement: ^9 || ^10
package: Custom

Replace My Custom Actions and the description with your desired name and description. The core_version_requirement specifies the Drupal versions your module is compatible with.

Step 3: Implement the Hook and Define the Action

In your my_custom_actions.module file, you'll need to implement the hook (hook_node_insert or hook_node_presave) and define your custom action using hook_action_info. Here's an example of how to define an action that sends an email notification when a new article node is created:

<?php

use Drupal\Core\Mail\MailManagerInterface; use Drupal\Core\Render\Markup; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Utility\Token; use Drupal\node\NodeInterface; use Symfony\Component\DependencyInjection\ContainerInterface;

/**

  • Implements hook_action_info(). */ function my_custom_actions_action_info() { return [ 'my_custom_actions_send_article_notification' => [ 'type' => 'node', 'label' => t('Send article notification'), 'configurable' => TRUE, 'hooks' => ['node_insert'], ], ]; }

/**

  • Implements hook_node_insert(). */ function my_custom_actions_node_insert(NodeInterface node) { if (node->getType() == 'article') \Drupal:service('plugin.manager.action') ->createInstance('my_custom_actions_send_article_notification') ->execute($node); }

/**

  • Executes the custom action to send an article notification.
  • @param \Drupal\node\NodeInterface $node
  • The node object. */ function my_custom_actions_send_article_notification(NodeInterface $node, array context) { config = \Drupal::config('my_custom_actions.settings')->get(); to=!empty(to = !empty(config['recipient_email']) ? config[&#39;recipient_email&#39;] : \Drupal::config(&#39;system.site&#39;)-&gt;get(&#39;mail&#39;); params['subject'] = t('New article created: @title', ['@title' => node-&gt;getTitle()]); params['body'] = t('A new article has been created on the site: @title. You can view it at @url.', [ '@title' => $node->getTitle(), '@url' => $node->toUrl('canonical', ['absolute' => TRUE])->toString(), ]);

$mailManager = \Drupal::service('plugin.manager.mail')->getInstance('php_mail'); $result = $mailManager->mail( 'my_custom_actions', 'article_notification', $to, 'en', $params, NULL, TRUE );

if ($result['result'] !== TRUE) \Drupal:logger('my_custom_actions')->error('There was a problem sending the email notification.'); }

Let's break down this code:

  • my_custom_actions_action_info(): This function defines the action. It returns an array with the action's machine name (my_custom_actions_send_article_notification), type (node), label (Send article notification), whether it's configurable (configurable set to TRUE), and the hooks it should be triggered by (hooks set to ['node_insert']).
  • my_custom_actions_node_insert(NodeInterface $node): This function implements the hook_node_insert hook. It checks if the node type is 'article' and, if so, executes the custom action.
  • my_custom_actions_send_article_notification(NodeInterface $node, array $context): This function contains the logic for the action. In this example, it sends an email notification with the article title and URL. It retrieves the recipient email from a configuration setting (which we'll define later) and uses Drupal's mail manager to send the email.

Step 4: Make the Action Configurable (Optional)

If you set configurable to TRUE in the hook_action_info implementation, you'll need to provide a configuration form for your action. This allows administrators to customize the action's behavior. Here's how to add a configuration form:

  1. Implement hook_form_FORM_ID_alter to alter the action configuration form. The FORM_ID is the action's machine name with action_ prepended (e.g., action_my_custom_actions_send_article_notification).
  2. Add form elements to your form to collect the configuration options.
  3. Save the configuration options in the my_custom_actions.settings configuration.

Here's an example:

/**
 * Implements hook_form_FORM_ID_alter().
 */
function my_custom_actions_form_action_my_custom_actions_send_article_notification_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $config = \Drupal::config('my_custom_actions.settings');
  $form['recipient_email'] = [
    '#type' => 'email',
    '#title' => t('Recipient Email'),
    '#description' => t('The email address to send notifications to.'),
    '#default_value' => $config->get('recipient_email'),
    '#required' => TRUE,
  ];

$form['#submit'][] = 'my_custom_actions_form_action_my_custom_actions_send_article_notification_submit'; }

/**

  • Submit handler for the action configuration form. */ function my_custom_actions_form_action_my_custom_actions_send_article_notification_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) { \Drupal::configFactory()->getEditable('my_custom_actions.settings') ->set('recipient_email', $form_state->getValue('recipient_email')) ->save();

\Drupal::messenger()->addMessage(t('Recipient email saved.')); }

This code adds a recipient_email field to the action configuration form and saves the value to the my_custom_actions.settings configuration.

Step 5: Enable the Module and Configure the Action

  1. Enable your custom module on the Extend page (/admin/modules).
  2. Go to the Actions page (/admin/config/workflow/rules/actions) and find your custom action.
  3. Click Configure to set the configuration options (if you made the action configurable).
  4. Go to the Triggers page (/admin/config/workflow/rules) and select the appropriate node type (e.g., Article).
  5. Find the After saving new content trigger (which corresponds to node_insert) or the Before saving content trigger (which corresponds to node_presave) and select your custom action.

Now, whenever a new node of the specified type is created, your custom action will be triggered.

Accessing Submitted Field Values

One common requirement when creating actions is to access the values of submitted fields. This allows you to make decisions based on the content of the node. To access field values, you can use the $node object passed to the hook implementation.

For example, if you have a field with the machine name field_author, you can access its value like this:

$author = $node->get('field_author')->getValue();

This will return an array of values for the field_author field. If the field is single-valued, you can access the first value like this:

$author_id = $node->get('field_author')->getValue()[0]['target_id'];

This assumes that field_author is an entity reference field and retrieves the target ID of the referenced entity.

You can then use these field values in your action logic. For example, you could send an email notification only if a specific checkbox field is checked or set a default value for a field based on the value of another field.

Common Challenges and Solutions

When creating actions, you might encounter some common challenges. Here are a few and their solutions:

  • Action not triggering: Ensure your module is enabled, the action is properly defined in hook_action_info, and the trigger is correctly configured on the Triggers page. Check the Drupal logs for any errors.
  • Accessing field values: Make sure you're using the correct field machine name and accessing the value in the appropriate way (e.g., using getValue() for field values and target_id for entity reference fields).
  • Error messages: Pay close attention to error messages in the Drupal logs. They often provide valuable clues about what's going wrong. Use debugging techniques, such as ddl() (Devel's dd() for Drupal 9 and 10), to inspect variables and data structures.
  • Performance: If your action performs complex operations, it could impact site performance. Consider using queues or asynchronous processing to offload tasks and prevent delays.
  • Security: Be mindful of security when creating actions. Sanitize user input and avoid directly executing arbitrary code based on user-provided data.

Best Practices

To ensure your actions are robust, maintainable, and performant, follow these best practices:

  • Keep actions focused: Each action should perform a single, well-defined task. This makes them easier to understand, test, and reuse.
  • Use configuration: If an action's behavior needs to be customized, make it configurable. This allows administrators to tailor the action to their specific needs without modifying the code.
  • Handle errors: Implement proper error handling in your actions. Log errors, display user-friendly messages, and prevent actions from crashing the site.
  • Test thoroughly: Test your actions in different scenarios to ensure they work as expected. Use automated tests to catch regressions and prevent bugs.
  • Document your code: Add comments to your code to explain what it does and why. This makes it easier for others (and your future self) to understand and maintain the code.

Example Use Cases

Here are a few example use cases for actions triggered by node_insert or node_presave:

  • Sending email notifications: Send an email to administrators or authors when new content is created or updated.
  • Creating related content: Automatically create related nodes based on the content of the current node.
  • Updating external systems: Synchronize content with external systems, such as CRM or marketing automation platforms.
  • Setting default field values: Automatically set default values for fields based on other field values or user roles.
  • Moderation workflows: Implement custom moderation workflows by changing node status or assigning roles based on content changes.

Conclusion

Creating actions on node_insert and node_presave in Drupal is a powerful way to automate tasks and build dynamic websites. By understanding the difference between these hooks, defining custom actions, accessing field values, and following best practices, you can create robust and maintainable actions that enhance your Drupal site's functionality. Remember to handle errors gracefully, test thoroughly, and document your code to ensure your actions are reliable and easy to maintain. By leveraging the power of custom actions, you can streamline content workflows, improve user experience, and build more engaging Drupal applications.

This article has provided a comprehensive guide to creating actions in Drupal triggered by node events. By following the steps and best practices outlined here, you can effectively automate tasks and enhance your Drupal website's functionality. Remember to leverage the power of custom actions to streamline your content workflows, improve the user experience, and build more engaging Drupal applications. Accessing submitted field values, as discussed, is a crucial aspect of creating dynamic actions that respond to the content being created or updated. By mastering these techniques, you can take your Drupal development skills to the next level.