Contacts in Joomla
Many Joomla users overlook the Contacts component. They see it as a simple place to store a name and an email address, so they reach for a third-party form extension instead. That is a missed opportunity.
The Contacts component (com_contact) is two things at once. It is a structured address book for the people and places behind your website: staff, offices, departments, and partners. And it is a working contact-form engine, where every entry can carry its own email form that sends mail to the right person. No extra extension needed.
From "show our office details" to per-contact email forms, user linking, and the developer model behind it.
This article explains how Joomla Contacts really work. It covers the basics for website owners, the practical setup for administrators, and the technical details for developers. You will learn how contacts and categories fit together, how the email form works, how display inheritance is resolved, how contacts link to user accounts, and how to avoid the most common mistakes.
1. The Basics
1.1 The Two Building Blocks
The component rests on two simple concepts. Once you understand how they relate, the rest falls into place.
| Concept | What it is | Database table |
|---|---|---|
| Contact | A single person or place (name, address, email, form). | #__contact_details |
| Category | A group of contacts (a com_contact category). | #__categories |
The relationship is easy to remember: a contact belongs to exactly one category. This is the same nested-set category tree that articles use.
1.2 How the Parts Fit Together
Here is the mental model:
Category ── Contact ──┬── Contact form → email
├── vCard → download
└── Linked user → profile + author articles
- Contact is the data: who they are, where they are, and how to reach them.
- Category is how you group contacts for list views and access control.
- Form is an optional per-contact email form.
- Linked user ties a contact to a
#__usersaccount.
A good way to keep the idea in your head: com_contact is a structured address book where every entry can also be a working contact form.
1.3 Where to Find It
In the Joomla 6 backend, you manage contacts and their categories here:
Components → Contacts → Contacts (the people and places)
Components → Contacts → Categories (grouping)
The front-end display is driven by menu items:
Menus → New → Contacts → (Single Contact / List / Featured / Categories)
1.4 What a Contact Actually Holds
The contact edit screen groups its fields into tabs:
| Tab | What it holds |
|---|---|
| Contact | Name, linked user, image, category, and the address block. |
| Misc | Free-text "miscellaneous information" in HTML. |
| Display | Which fields and links to show on the front end. |
| Form | Whether the email form appears, and how it behaves. |
| Publishing | Author, dates, and metadata. |
The address block itself covers: position, address, suburb, state, country, postcode, telephone, mobile, fax, email, and webpage.
Back to top2. Creating Contacts
2.1 Create a Category First
A contact must live in a category, so set one up before you add people:
Components → Contacts → Categories → New
- It is an ordinary Joomla category with
extension = com_contact. - It uses the same nested tree, the same ACL, and the same Rebuild button as article categories.
2.2 Create the Contact
Now add the contact itself:
Components → Contacts → Contacts → New
Only two fields are required:
- Name: the person or place.
- Category: which com_contact category it lives in.
Everything else (address, email, image, links) is optional, but it is exactly what makes the contact useful.
2.3 The Five "Link" Slots
Beyond the standard address fields, each contact has five generic link fields. Each one is a URL plus a label:
linka / linka_name e.g. https://linkedin.com/... "LinkedIn"
linkb / linkb_name e.g. https://github.com/... "GitHub"
linkc ... linke
These are great for social profiles or "see also" links without creating custom fields.
2.4 Featured Contacts
You can toggle Featured (a star) on any contact. A Featured Contacts menu item then lists only those. It is the same pattern as featured articles: a curated subset shown on top of the full list.
2.5 Custom Fields Work Here Too
The Contacts component is fields-enabled, so you can extend it without code:
Components → Fields → (select "Contacts")
- Add typed fields (text, list, calendar, media, and more) to all contacts or per category.
- They render automatically on the contact view and can also appear on the form.
For the field-group and per-category logic, see the separate "Focus on Custom Fields" article.
Back to top3. Displaying Contacts
3.1 A Contact Does Nothing Without a Menu Item
Like most Joomla content, a contact is just data until a menu item (or a module or plugin) renders it. There are four menu item types:
| Menu item type | What it shows |
|---|---|
| Single Contact | One contact's full detail and form. |
| List Contacts in a Category | A table or list of one category. |
| Featured Contacts | All contacts flagged as Featured. |
| List All Contact Categories | The category tree as links. |
3.2 The Single Contact View
The single contact view is driven by the contact's Display tab plus the menu item options. A typical layout looks like this:
[ image ] Name
Position
Address block (each line toggleable)
Telephone / Mobile / Fax / Email / Webpage
Misc information
Links (linka...linke)
Contact form
Every line has a Show / Hide / Use Global setting. The global defaults live in the component Options.
3.3 The Three-level Display Inheritance
Whether a single field shows is resolved in this order, from most specific to most general:
Contact (Display tab) Show / Hide / Use Global
└─ Menu item options Show / Hide / Use Global
└─ Component Options (global default)
"Use Global" is the glue. Set a value once in Options, then override it per menu item or per contact only where you actually need to.
3.4 List and Category Views
- The List view shows a sortable table: name, position, phone, and so on.
- Columns, the search filter, and pagination are all menu item options.
- The Categories view renders the tree, where each node links to its own list.
3.5 vCard Download
Each contact can offer a downloadable vCard (a .vcf file). This is the standard format that every address book imports.
allow_vcard = 1 → "Download contact details" link on the contact view
- Joomla ships a dedicated view for it:
src/View/Contact/VcfView.php. - It serialises the name, position, address block, phone, email, and webpage into a
.vcffile. - Visitors click once and the contact lands straight in their phone or mail client.
Toggle Allow vCard Download on the Display tab (or globally in Options). One field, zero extra work: a directory that exports itself.
Back to top4. The Contact Form and Email
4.1 The Form Is the Killer Feature
Each contact can expose an email form. When a visitor submits it, Joomla sends a mail to that contact's address. You do not need a third-party form extension.
Visitor fills form → Joomla validates → email to contact → optional copy/reply
You turn it on from the contact's Form tab, or globally in Options.
4.2 Where the Mail Goes
The recipient is the contact's own address, stored in the email_to field. This is an important detail: the mail goes to email_to, not to the linked user's account email.
The Form tab gives you several options:
| Option | Effect |
|---|---|
| Show Contact Form | Master on/off switch for this contact. |
| Send Copy to Submitter | Send the visitor a copy of their own message. |
| Banned Email / Subject / Text | Simple spam filters (blocklists). |
| Session Check | Require a valid session (validate_session) as an anti-bot measure. |
| Custom Reply | Suppress Joomla's auto-reply so a plugin or integration can handle it. |
4.3 The Redirect After Submit
The redirect field sets where the visitor lands after a successful submit:
- Empty: back to the contact page with a "thank you" message.
- Set: a custom "thank you" page, which is handy for conversion tracking.
4.4 Built-in Spam Mitigation
Contacts ship with lightweight defenses that need no CAPTCHA to be useful:
- CSRF token: every submit calls
checkToken()inContactController::submit(). A forged or stale POST is rejected before anything else runs. - Banned email / subject / text: substring blocklists, set per contact.
- Session check: rejects posts that have no live Joomla session, which kills naive bots.
- CAPTCHA plugin: if a global CAPTCHA (for example reCAPTCHA) is set, the form uses it automatically.
The CSRF token is always on. Layer the session check and a global CAPTCHA on top, and you stop most spam without any extra extensions.
4.5 Email Cloaking
Email addresses shown on the page run through the Email Cloaking content plugin:
This email address is being protected from spambots. You need JavaScript enabled to view it. → obfuscated JS → rendered to humans, hidden from scrapers
- The
add_mailto_linksetting controls whether the address becomes a clickablemailto:link. - Cloaking is on by default: harvesters see scrambled markup, while visitors see the real address.
5. Categories and Access Control
5.1 Contacts Use the Shared Category System
Contact categories are ordinary Joomla categories with extension = com_contact:
#__categories WHERE extension = 'com_contact'
That means they share the same nested tree, the same Rebuild button, and the same ACL machinery as article categories.
5.2 Why Categories Matter Here
- A List or Categories menu item targets a category, and that becomes your directory.
- You can organise by department, office, region, or team.
- Permissions inherit down the tree (Create, Edit, Edit State, Delete).
For the lft and rgt nested-set details, see the "Focus on Categories" article.
5.3 Access and Language
- The Access level on a contact controls who can view it.
- The Language setting lets a contact appear only on its matching site language.
- Combine the two on a multilingual site: one structure, with people filtered by language.
6. Plugins and Integrations
6.1 Contacts Is a Small Ecosystem
Six core plugins extend com_contact:
| Plugin | Type | What it does |
|---|---|---|
| Contact | content | Shows the author's contact box under an article. |
| Contact Creator | user | Auto-creates a contact when a user registers. |
| Contact | editors-xtd | Editor button to insert a link to a contact. |
| Contacts | finder | Smart Search indexer for contacts. |
| Contact | privacy | Exports and removes contact data for GDPR requests. |
| Contact | webservices | Enables the REST API routes. |
6.2 Linking a Contact to a User
The user_id field ties a contact to a #__users account:
Contact.user_id → #__users.id
This link unlocks several features:
- Show User Custom Fields: the user's profile fields appear on the contact page.
- The Contact content plugin: an "About the author" box links articles back to the contact.
- A single identity: the person's login account and their public contact entry are the same person.
6.3 Contact Creator: Automatic Profiles
The Contact Creator plugin lives at plugins/user/contactcreator:
- On user registration, it auto-creates a linked contact.
- It is configurable: you choose the target category, whether to autopublish, and whether to auto-fill the webpage.
It hooks into Joomla's user event:
onUserAfterSave → ContactCreator → insert #__contact_details (user_id linked)
This is a clean example of an event-driven plugin: every new member becomes a directory entry without any manual data entry.
6.4 The "About the Author" Plugin
The content plugin at plugins/content/contact lets an article display its author's contact:
Article.created_by → Contact.user_id → render contact box / link
You configure it globally (position, and whether it links or embeds). It bridges com_content and com_contact through the shared user id.
6.5 Smart Search and Privacy
- The Finder plugin indexes contacts, so they appear in site search results.
- The Privacy plugin makes contacts part of GDPR export and removal requests. This matters, because a contact can hold a real person's data.
7. Under the Hood (Developer View)
7.1 One Main Table
The contacts themselves live in a single table:
#__contact_details the contacts (people/places) + form/display params
Plus rows in the shared #__categories (with extension = com_contact), and the #__fields* tables when custom fields are used.
7.2 Key Columns in #__contact_details
The most important columns are:
id, name, alias identity + SEF slug
catid category id (→ #__categories)
user_id linked Joomla user (→ #__users), 0 = none
con_position job title / position
address, suburb, state,
country, postcode the address block
telephone, mobile, fax phone numbers
email_to form recipient address
webpage website URL
image photo / logo
misc free HTML "miscellaneous" block
linka...linke / *_name five generic URL + label slots
default_con the category's default contact
featured featured flag
sortname1/2/3 fields for custom sorting (e.g. last name)
params JSON: every show_* toggle + form options
metakey/metadesc/metadata SEO + robots
published, access, language, ordering, hits, version
publish_up / publish_down scheduling window
7.3 The MVC Layout
The component is split into an administrator side and a site side:
administrator/components/com_contact/ ← manage contacts + categories
src/Model/ContactModel.php, ContactsModel.php
src/Table, src/Controller, tmpl/, forms/contact.xml
components/com_contact/ ← front-end views
src/Model/ContactModel.php (single contact + form submit)
src/Model/CategoryModel.php (list in a category)
src/Model/FeaturedModel.php (featured list)
src/Model/CategoriesModel.php (category tree)
src/Controller/ContactController.php (form POST handler)
plugins/... ← the six integrations
Note how the five site models map almost one-to-one onto the four menu item types, with the contact model also handling the form submit.
7.4 The Form Submission Flow
When a visitor submits a contact form, the request follows this path:
POST /index.php?option=com_contact&task=contact.submit&id=42
→ ContactController::submit()
→ validate (session check, banned words, CAPTCHA)
→ build + send email (Joomla Mailer)
→ optional copy to submitter
→ redirect (custom URL or back with message)
The component's own controller, not a generic form component, owns the validation and the mailing.
7.5 SEF URLs and the Router
Contact URLs are built and parsed by the component's router:
components/com_contact/src/Service/Router.php
It turns query strings into clean, human-readable paths and back again:
index.php?option=com_contact&view=contact&id=7 ↔ /contact/support/peter-martin
The router is responsible for three jobs:
- Build: generate SEF links for contacts, categories, and featured views.
- Parse: resolve an incoming SEF path back to the right view and id.
- Menu resolution: prefer an existing menu item's segment over a generic path.
Because routing lives inside the component, contact links survive category moves and respect your menu structure automatically.
7.6 Web Services API (Headless)
The component ships REST routes, enabled by the webservices plugin:
api/components/com_contact/src/Controller/ContactController.php
GET /api/index.php/v1/contact/contacts
GET /api/index.php/v1/contact/contacts/{id}
POST /api/index.php/v1/contact/contacts (create)
This opens the door to modern architectures:
Joomla API → React / Vue directory → custom contact rendering
The data lives in Joomla, but the delivery can live anywhere. Keep in mind that API delivery bypasses the built-in form mailer, so you handle form submissions yourself.
7.7 Programmatic Access
The same nested-set Categories API works for contacts:
use Joomla\CMS\Categories\Categories;
$categories = Categories::getInstance('Contact');
$node = $categories->get('staff'); // by alias or id
$children = $node->getChildren();
And the table and model classes live under these namespaces:
Joomla\Component\Contact\Administrator\Table\ContactTable
Joomla\Component\Contact\Site\Model\ContactModel
7.8 Template Overrides
Every view is overridable per template:
components/com_contact/tmpl/contact/default.php
templates/<your_template>/html/com_contact/contact/default.php ← override
The single-contact view is split into sub-layouts (_address, _user_custom_fields, _links, and more), so you can override just the address block or just the form, instead of the whole page. The rule of thumb: override the view, not the model. Data and presentation stay separate.
7.9 At Scale
The data model is simple, but a few things bite on large directories with thousands of contacts:
| Concern | Why | Mitigation |
|---|---|---|
| List query cost | Category and featured views filter and sort big result sets. | Index catid, published, access, language. |
| User-link lookups | "Articles by author" and profile joins use user_id. |
Index user_id (0 = none is common, so keep it indexed). |
| Custom-field joins | #__fields_values grows per contact times per field. |
Limit fields shown in list views; render on demand. |
| Category depth | Deep nested trees widen lft/rgt scans. |
Keep the tree shallow; Rebuild after bulk moves. |
Contacts are read-heavy and write-light. Cache the views and index the filter columns, and the component scales comfortably.
Back to top8. Common Mistakes and Pitfalls
8.1 "The Contact Form Doesn't Appear"
Work through this checklist:
- Is Show Contact Form enabled (on the contact's Form tab, and not hidden globally)?
- Does the contact have an email_to address?
- Is the menu item a Single Contact? List views do not show the form.
- Is a mis-set Use Global hiding it at a higher level?
8.2 "The Email Never Arrives"
- Is the site mail configured, and not silently failing? Check with a tool like MailHog locally.
- Are the banned text, subject, or email filters rejecting it?
- Is the session check failing for a cached or anonymous post?
- Remember the recipient is
email_to, not the linked user's address. Verify that it is actually set.
8.3 Display Confusion
- The three-level Show / Hide / Use Global inheritance trips up everyone. Check all three layers.
- A blank single-contact page usually means everything is set to Hide.
- Linked-user custom fields only show if both the link and "Show User Custom Fields" are on.
8.4 Privacy and Data
- A contact can hold a real person's personal data, so include it in your privacy policy.
- The Privacy plugin must be enabled for GDPR export and removal to cover contacts.
- Email cloaking protects the display, but the address is still stored in the database in plain text.
9. Best Practices
If you only remember a few things from this article, remember these:
- Create a category before you add contacts; every contact must live in one.
- The form recipient is
email_to, not the linked user's account email. - Master the three-level Show / Hide / Use Global inheritance: set defaults once in Options, override only where needed.
- Link contacts to users to unlock profiles, author boxes, and a single identity.
- Enable the Privacy plugin so contacts are covered by GDPR export and removal.
- Index the filter columns on large directories, and keep the category tree shallow.
10. Quick Reference
CONTACT Components → Contacts → Contacts → New
CATEGORY Components → Contacts → Categories (extension=com_contact)
DISPLAY Menus → New → Contacts → Single / List / Featured / Categories
FORM Contact → Form tab → Show Contact Form (+ email_to)
RECIPIENT email_to (NOT the linked user's address)
LINK USER Contact.user_id → #__users.id
INHERIT Contact → Menu item → Component Options (Use Global)
FEATURED star a contact → Featured Contacts menu item
VCARD allow_vcard → downloadable .vcf (VcfView)
LINKS linka...linke (+ _name labels), five slots
FIELDS Components → Fields → Contacts (custom fields)
PLUGINS contactcreator (onUserAfterSave), content/contact (author box), finder, privacy
SPAM CSRF token (always) + banned words + session check + CAPTCHA
CLOAK Email Cloaking content plugin (on by default)
ROUTER src/Service/Router.php → SEF /contact/<cat>/<alias>
OVERRIDE templates/<tpl>/html/com_contact/contact/default.php
INDEXES catid, user_id, published, access, language
API /api/index.php/v1/contact/contacts
TABLE #__contact_details (+ #__categories)
Back to top11. Summary
Joomla Contacts is a structured address book and a contact-form engine in one, hiding in plain sight. Once you see it that way, you stop reaching for extra extensions for jobs the core already does well.
It gives you:
- Structure: typed fields, an address block, five link slots, and custom fields.
- Forms: per-contact email forms with spam mitigation, no extension needed.
- Identity: link contacts to users, auto-create profiles, and show author boxes.
- Display: four menu views with three-level Show / Hide inheritance.
- Integration: a shared Categories tree, ACL, Smart Search, Privacy, and a REST API.
- Privacy: email cloaking plus GDPR export and removal out of the box.
If you are building a staff directory, a member list, or simply want a reliable contact page that emails the right person, the Contacts component is worth a fresh look. It is the quiet, well-built address book that has been part of Joomla all along.
Back to top

Joomla specialist and Linux admin for fast, secure and scalable websites.


