Create An Action On 'node_insert' Or 'node_presave'
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
- Create a new directory in the
modules/custom
directory of your Drupal installation. Name it something descriptive, likemy_custom_actions
. - 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
}
/**
- 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();
config['recipient_email']) ? config['recipient_email'] : \Drupal::config('system.site')->get('mail');
params['subject'] = t('New article created: @title', ['@title' => node->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
}
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 toTRUE
), and the hooks it should be triggered by (hooks
set to['node_insert']
).my_custom_actions_node_insert(NodeInterface $node)
: This function implements thehook_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:
- Implement
hook_form_FORM_ID_alter
to alter the action configuration form. TheFORM_ID
is the action's machine name withaction_
prepended (e.g.,action_my_custom_actions_send_article_notification
). - Add form elements to your form to collect the configuration options.
- 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
- Enable your custom module on the Extend page (
/admin/modules
). - Go to the Actions page (
/admin/config/workflow/rules/actions
) and find your custom action. - Click Configure to set the configuration options (if you made the action configurable).
- Go to the Triggers page (
/admin/config/workflow/rules
) and select the appropriate node type (e.g., Article). - Find the After saving new content trigger (which corresponds to
node_insert
) or the Before saving content trigger (which corresponds tonode_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 andtarget_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'sdd()
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.