Drupal Odyssey is supported by it's readers. When you purchase products or services using the links on this site, we may earn a small commission at no additional cost to you. Learn more
In the last post, I shared my journey of building the UTM Sets feature to eliminate tedious manual work. That was the "why." This post is the "how." Today, I'm going to pull back the curtain on the key components that make the whole system work: the Shortlink content entity, the controller that handles the redirects, and the service that keeps everything clean and organized – all tied together by the auto-generate form. Think of it as the data model, the helpful utility, and the conductor. This is a step-by-step look at how you can build a URL shortener in Drupal from the ground up.
The Shortlink Content Entity: Your Data Model
At the heart of the system is the Shortlink content entity. If you're a Drupal developer, you know this is where the action starts. A content entity is Drupal's way of storing and managing user-generated data, and in this case, it represents a single shortlink.
This non-fieldable content entity is where the magic of linking to other entities happens. The entity reference field, utm_set
, connects this shortlink directly to your pre-configured UTM Set. This is the central piece that links the UTM automation from our last post to the actual redirect.
Key fields on this entity include:
path: The unique, human-readable slug for the shortlink.
utm_set: Our entity reference to the UTM Set we created.
target_entity_type & target_entity_id: This allows a single shortlink to point to any content or configuration entity on the site, such as a blog post or a product page.
destination_override: A field for a custom path, giving me the flexibility to point to external URLs or specific internal paths that aren't tied to an entity.
This entity isn't just a simple data bucket; its resolveDestinationUrl()
method intelligently figures out where the user should go, checking for an override first and then falling back to the canonical URL of the target entity. This logic is a great example of keeping related functionality right where it belongs.
Module Configuration: Setting the Stage For The Show
Before you can get to the magic of auto-generation, you need to set the global rules for your shortlinks. That's the job of the ShortlinkSettingsForm. This is your module's central control panel, and it's where you decide the basic behaviors for every shortlink on your site.
This form handles key configurations like the path prefix—the part of the URL that comes before the unique slug. It also lets you choose the default HTTP redirect status (301, 307, etc.), which is a critical detail for SEO and browser caching. Most importantly, this is where you select which content entity types (like "node" or "media") are even available to be configured for automatic shortlink generation!. This setup ensures that your site has a single, consistent way of handling shortlinks.
The User Experience Magic: The Auto Generation Form
The Shortlink content entity is all fine and good and is usable by itself, the real magic for me was automating the process. This is where the ShortlinkAutoGenerateForm comes in. While the UTM Set entity provides the reusable data structure, this form is the user-facing bridge that connects the automation to your content.
This form allows site administrators to decide which content types – like blog posts, news articles, or product pages – should automatically get a shortlink. You can even configure a specific UTM Set to be applied by default, ensuring that every time a new blog post is created, it's not only getting a shortlink but is also instantly trackable.
The form's code dynamically loads all your site's content types and bundles, presenting them in a clean, vertical tab interface. This is where you configure which entities will have a shortlink automatically created and which UTM Set to apply. It's the simple, "set-it-and-forget-it" piece of the puzzle that makes the whole module so powerful.
Wiring It Up
The settings on this form are implemented using hook_entity_insert()
in the .module file; specifically shortlink_manager_entity_insert()
. This hook is triggered every time an entity is saved. This implementation checks to see if the saved entity is an instance of ContentEntityBase (which is what every content entity in Drupal is based from).
If the entity meets the criteria, the function performs the following steps:
- It checks the configuration to see if shortlink auto-generation is enabled for the specific content type and bundle of the new entity.
- It retrieves the selected UTM Sets from the configuration.
- It then loops through each selected UTM Set, creating a new Shortlink entity for each one.
- Each new Shortlink entity gets a unique path and is linked to the newly created content entity and the appropriate UTM Set.
- Finally, the new shortlinks are saved, automatically making them live and trackable on the site.
This small function is the behind-the-scenes engine that connects all the pieces. It listens for your content authors creating new material and, based on your configured rules, it instantly and effortlessly generates your smart shortlinks.
The ShortlinkRedirectController: The Conductor
A shortlink is useless if it doesn't do its job – redirecting the user. That's where the ShortlinkRedirectController steps in. Its single job is to act as the conductor, directing the incoming request to the correct destination.
The controller's redirectShortlink()
method is the workhorse. Here's a quick look at its thought process when a user clicks a link:
Find the link: It queries the database for the unique shortlink path.
Determine the destination: It first checks for a destination_override
on the shortlink entity. If one exists, it uses that. If not, it loads the target entity (node, user, etc.) and gets its canonical URL.
Apply the UTMs: It then checks if the shortlink has an associated UTM Set. If it does, it grabs the parameters and applies them to the destination URL's query string.
Redirect: Finally, it sends the user on their way with a clean and informative redirect response.
This separation of concerns – storing the data in the entity and handling the request in the controller – is a core principle of good Drupal architecture.
The ShortlinkManager Service: The Helpful Utility
You might be asking yourself: how do we ensure every shortlink path is unique? That's what the ShortlinkManager service is for. A service in Drupal is a reusable helper class that provides common functionality across your application.
My ShortlinkManager service contains a crucial method: generateShortlinkPath()
. This method creates a random, unique string and adds a configurable prefix, guaranteeing that every new shortlink has its own unique, conflict-free path. The service also contains the pathExists()
method, a simple database query to double-check for uniqueness before a path is saved. This is a perfect example of keeping a specific, reusable task outside of the entity or controller, so it can be called from anywhere in the module.
The power of this module lies in how these three pieces work together. The service provides the helper method to the entity to create the path, and the controller then uses the logic in the entity to handle the redirect. It's a cohesive system where each part has a clearly defined role.
What's Next?
In my next post, I'll cover a few final items that are the icing on the cake for this module that make it easier for content authors to benefit from all of this functionality that we've added as well as some thoughts on how this module could be enhanced and/or extended to customize it and make it work for your workflows.
I've covered a lot of ground here, but I hope this gives you a clear picture of how I built this module from the ground up. What are your thoughts on this architecture? Leave a comment below.
0 Comments
Login or Register to post comments.