Categorization in Drupal is one of those things that looks fine on the surface but gets messy fast. Editors are busy, categories get picked in a hurry, and before long you've got a dozen articles filed under the wrong taxonomy term or spread inconsistently across three different ones that mean almost the same thing.
The fix isn't enforcing stricter rules on editors. It's removing the guesswork entirely.
In this tutorial, I'll walk you through building a custom Drupal 11 module that reads a node's actual content and uses OpenAI to pick the most appropriate category automatically, no manual selection needed.
It hooks into the node save process, pulls your existing taxonomy terms, and asks the AI to match the content against them. The result gets assigned before the node is stored. It's a small module but it solves a real problem, especially on sites with large editorial teams or high publishing volume.
What This Module Will Do
Our AI category system will:
- Analyze node body content on save
- Compare it against existing taxonomy terms
- Recommend the most relevant category
- Automatically assign it (or display it to editors)
Use cases include:
- Blog posts
- Documentation pages
- News articles
- Knowledge bases
Prerequisites
Make sure you have:
- Drupal 11
- PHP 8.1+
- Composer
- A taxonomy vocabulary (example: categories)
- An OpenAI API key
Step 1: Create the Custom Module
Create a new folder:
/modules/custom/ai_category/
Inside it, create the below files:
- ai_category.info.yml
- ai_category.module
ai_category.info.yml
name: AI Category Recommendation
type: module
description: Automatically recommend and assign taxonomy categories using AI.
core_version_requirement: ^11
package: Custom
version: 1.0.0
Step 2: Hook Into Node Save
We’ll use hook_entity_presave() to analyze content before it’s stored.
ai_category.module
use Drupal\Core\Entity\EntityInterface;
use Drupal\taxonomy\Entity\Term;
/**
* Implements hook_entity_presave().
*/
function ai_category_entity_presave(EntityInterface $entity) {
if ($entity->getEntityTypeId() !== 'node') {
return;
}
// Only apply to articles (adjust as needed)
if ($entity->bundle() !== 'article') {
return;
}
$body = $entity->get('body')->value ?? '';
if (empty($body)) {
return;
}
$category = ai_category_recommend_term($body);
if ($category) {
$entity->set('field_category', ['target_id' => $category]);
}
}
This ensures our logic runs only for specific content types and avoids unnecessary processing.
Step 3: Ask AI for Category Recommendation
We’ll send the node content plus a list of available categories to OpenAI and ask it to pick the best one.
function ai_category_recommend_term(string $text): ?int {
$apiKey = 'YOUR_OPENAI_API_KEY';
$endpoint = 'https://api.openai.com/v1/chat/completions';
$terms = \Drupal::entityTypeManager()
->getStorage('taxonomy_term')
->loadTree('categories');
$categoryNames = array_map(fn($t) => $t->name, $terms);
$prompt = "Choose the best category from this list:\n"
. implode(', ', $categoryNames)
. "\n\nContent:\n"
. strip_tags($text)
. "\n\nReturn only the category name.";
$payload = [
"model" => "gpt-4o-mini",
"messages" => [
["role" => "system", "content" => "You are a content classification assistant."],
["role" => "user", "content" => $prompt]
],
"temperature" => 0
];
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Authorization: Bearer {$apiKey}"
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 15
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
$chosen = trim($data['choices'][0]['message']['content'] ?? '');
foreach ($terms as $term) {
if (strcasecmp($term->name, $chosen) === 0) {
return $term->tid;
}
}
return null;
}
What’s happening here:
- Drupal loads all available categories
- AI receives both content + allowed categories
- AI returns one matching category name
- Drupal maps it back to a taxonomy term ID
Step 4: Enable the Module
- Place the module in /modules/custom/ai_category
- Go to Extend → Enable module
- Enable AI Category Recommendation
- That’s it — no UI needed yet.
Step 5: Test It
- Create a new Article
- Write content related to PHP, Drupal, AI, or CMS topics
- Click Save
- The Category field is auto-filled
Example:
Article content:
“This tutorial explains how to build a custom Drupal 11 module using PHP hooks…”
AI-selected category:
Drupal
Optional Enhancements
Once the basics work, you can extend this system:
- Show AI recommendation as a suggestion, not auto-assignment
- Add admin settings (API key, confidence threshold)
- Use Queue API for bulk classification
- Switch to embeddings for higher accuracy
- Log category confidence scores
- Support multi-term assignment
Security & Performance Tips
- Never hard-code API keys (use settings.php or environment variables)
- Limit text length before sending to AI
- Cache recommendations to reduce API calls
- Add fallbacks if the AI response is invalid
Comments · 0
Post a Comment