Contacts, Banners and News Feeds

This content was generated with the assistance of AI and should be verified against the official Joomla documentation before being relied on in production.

This sub-section’s Joomla bibliography lists the reference material consulted while preparing these pages.

Joomla ships three small content components next to Articles: Contacts (com_contact) for people and contact forms, Banners (com_banners) for advertising with impression and click statistics, and News Feeds (com_newsfeeds) for displaying external RSS and Atom feeds. A fourth, Weblinks (com_weblinks), used to live in the same family and is now a separate extension. This page was checked on 2026-10-30 against Joomla 6.2.x (PHP 8.3 or later, see Requirements and hosting), the Joomla! User Guide and the 6.2 source tree.

The running example is the Tallpine Hiking Club: a board of volunteers published as contacts, a "Contact the club" form that reaches the secretary, banners for two partner shops, and a sidebar that shows the park authority’s trail closures feed.

Where the documentation is thin

The User Guide pages for these components are short introductions: Contacts describes the edit form and the four menu item types, Banners describes what an impression and a click-through are, and News Feeds describes the Feed Display module and the two menu item types. The option lists, the form-handling code and the database tables are documented only in the component’s XML files and source. This page therefore cites the source tree (administrator/components/com_contact/config.xml and similar) where the Guide is silent. Older books such as Joomla! 4 Masterclass (2023) describe these screens for Joomla 4; the screens are largely unchanged, but their documentation links (docs.joomla.org/J4.x) are legacy wiki pages, and Joomla 4 itself reached end of life in October 2025.

Contacts

What it is

A contact is a record in #__contact_details: name, alias, position, address fields, telephone, mobile, fax, web page, image, free text (misc), an email_to address, an optional link to a Joomla user (user_id), a category, an access level, a language and three sort-name fields. Contacts serve two purposes: a public "business card" page, and a mail form that delivers a visitor’s message to the contact without exposing the address. Site builders create contacts and menu items, editors maintain them, administrators configure spam protection and mail delivery.

Screens and menu item types

Contacts live under Components > Contacts, with Contacts and Categories lists plus Fields and Field Groups for custom fields (the com_contact.contact and com_contact.mail contexts, see Custom fields). The edit form has tabs for the main details, Miscellaneous Information, Display, Form, Publishing and the custom-field tab. The Contact Display menu item types are Single Contact, Featured Contacts, List Contacts in a Category and List All Contacts in a Category Tree (see Menus and menu items). Contacts in categories use the same nested categories, access levels and tags as articles (Categories and tags).

The Sort Name option orders by the three sort fields (so "surname, first name" ordering works even when the display name is "First Surname"); Ordering follows the list order and Featured Contacts Ordering shows featured contacts first. A menu item’s sort setting overrides the component option when it is set.

For the Tallpine board, a nested category structure keeps the committee readable:

Board                      (category, access: Public)
  Executive                (category) -> Chair, Secretary, Treasurer
  Trail Wardens            (category, access: Trail Warden)

Linking a contact to a user

If the contact’s user_id is set and email_to is empty, the form controller falls back to the linked user’s registered address. The User - Contact Creator plugin can create a contact automatically when a user registers. Keep email_to empty only when the user’s login address is the right public mail destination; otherwise set it explicitly.

The Display and Form options

Each of these exists as a component option (the Options toolbar button), as a per-contact override and as a menu item override, with the menu item winning when the contact is shown through its own menu item. Key names from config.xml and forms/contact.xml:

Group Names

Contact

show_name, show_position, show_email, add_mailto_link, show_street_address, show_suburb, show_state, show_postcode, show_country, show_telephone, show_mobile, show_fax, show_webpage, show_image, show_misc, allow_vcard, show_articles, articles_display_num, show_profile, show_user_custom_fields, show_links, contact_layout

Form

captcha, show_email_form, show_email_copy, banned_email, banned_subject, banned_text, validate_session, custom_reply, redirect

Category and list

show_category_title, show_description, show_headings, filter_field, show_pagination, contacts_display_num, initial_sort, column toggles such as show_email_headings

Integration

show_feed_link, sef_ids, custom_fields_enable

Showing the e-mail address, the telephone number or the postcode of a private individual is personal-data processing. Hide what is not needed (show_email off while the form stays on is the usual choice), and see Privacy and action logs.

How the contact form works internally

The form is defined by components/com_contact/forms/contact.xml with the fields contact_name, contact_email (validated by the ContactEmail rule), contact_subject (ContactEmailSubject), contact_message (ContactEmailMessage), the checkbox contact_email_copy and a captcha field. The submit task is ContactController::submit(), and the sequence is fixed:

sequenceDiagram participant V as Visitor participant C as ContactController submit participant F as Form rules participant P as Contact plugins participant M as MailTemplate V->>C: POST jform with token C->>C: checkToken C->>C: show_email_form on? C->>C: validate_session, session active? C->>F: validate form and captcha F->>F: banned email, subject, text C->>P: onValidateContact C->>P: onSubmitContact alt custom_reply is off C->>M: com_contact.mail to email_to C->>M: com_contact.mail.copy to sender end C->>V: redirect or message
  • checkToken() rejects forged posts.

  • If the effective show_email_form is off, the visitor is redirected to the contact page and nothing is sent.

  • With validate_session on, a request without an active session is refused with a warning and the entered data is put back in the session (the point is to reject bots that do not keep cookies, at the price of rejecting visitors who block cookies).

  • The form is validated, including the banned rules. banned_email, banned_subject and banned_text are semicolon-separated lists; the rule classes reject a submission when the address, subject or message contains one of the items, using a case-insensitive substring match. A short entry therefore blocks more than expected: ass blocks "passes".

  • onValidateContact is dispatched to plugins of the contact group; a plugin adds an exception as a result to reject the submission.

  • onSubmitContact is dispatched with the validated data so plugins can forward it (to a CRM, for example).

  • Unless custom_reply is on, Joomla sends two mails through the mail templates com_contact.mail and com_contact.mail.copy (the copy only when show_email_copy allows it and the visitor ticked the box). The template data holds sitename, name, contactname, email, subject, body, url and customfields; name, e-mail and body are registered as unsafe tags, which means they are escaped. The reply-to is the visitor, not the site. With custom_reply on, nothing is sent and a plugin is expected to handle the message itself.

  • If the redirect option is set, the visitor is sent there after submission; otherwise back to the previous page.

Edit the subject line and body in the mail templates (see Mail templates and e-mail settings). Mail that is never delivered is usually a mail-settings problem (SMTP, SPF) rather than a contact setting.

Spam protection in layers

Layer Notes

Form token

Always on; defeats cross-site forgery but not bots that load the page first.

Validate session

Cheap and invisible; may reject visitors without cookies.

Captcha

Select a captcha plugin per contact, per menu item or globally (captcha; the value 0 means "do not use"). The reCAPTCHA plugin was removed from core in 5.0, and a Proof-of-Work captcha plugin arrived in 6.1 (see Security hardening).

Banned lists

Substring matches; useful for obvious spam phrases, easy to over-block.

Contact plugin

A custom validation rule such as the honeypot below.

The following plugin rejects any submission where a hidden field that humans cannot see has been filled in. It belongs in the contact plugin group. Add the field to the form with a template override of the contact form layout.

<?php

namespace Tallpine\Plugin\Contact\Honeypot\Extension;

use Joomla\CMS\Event\Contact\ValidateContactEvent;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;

\defined('_JEXEC') or die;

final class Honeypot extends CMSPlugin implements SubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return ['onValidateContact' => 'onValidateContact'];
    }

    public function onValidateContact(ValidateContactEvent $event): void
    {
        $data = $event->getData();

        if (!empty($data['tallpine_website'])) {
            $event->addResult(new \RuntimeException(Text::_('PLG_CONTACT_HONEYPOT_REJECTED')));
        }
    }
}

Note that onValidateContact is for validation only: modifying the data there is deprecated, and onSubmitContact (with updateData()) is the place to change it. Both events are concrete event classes since Joomla 5.0 (older code reads arguments from a generic event, which is removed in 7.0).

The core contact form has no consent checkbox. The System - Privacy Consent plugin (privacyconsent) adds a consent checkbox to user registration and profile editing, and it is not wired to com_contact. To record agreement with a privacy notice on the contact form, add a custom field of type Checkbox, required, in the context Contact: Mail (com_contact.mail) with a label that links the policy article. The value is included in the mail in the customfields template tag, so the secretary sees that the box was ticked. The Privacy component, its consent records, data requests and the privacy plugins (including one that exports and removes a user’s contact data) are covered in Privacy and action logs.

Common mistakes

  • The contact form does not appear: the contact has no resolvable e-mail destination, show_email_form is off at the contact, the menu item or the options level, or the Form tab is overridden by a menu item.

  • The mail arrives in spam: the site’s From address and SMTP configuration, not the contact, decide this.

  • Banned words reject legitimate messages: remove short or common fragments; remember matching is by substring.

  • Showing email_to through the "e-mail" display option exposes the address to scrapers; the content plugin that cloaks addresses applies to the display only.

  • Contacts in an access level or language the visitor does not have are invisible, so the board page can look empty after a multilingual switch (see Multilingual sites).

Banners

What it is

The Banners component records advertisements as a banner (an image or a block of custom code, a click URL, a category and a validity window) optionally owned by a client (an advertiser with a contact person and e-mail). The site displays banners through the Banners module (mod_banners) and counts impressions and clicks. Banners are the only built-in way to sell and report on placements; the User Guide describes them as simple text or images and notes that the host earns a small payment per impression and a larger one per click. Many sites no longer need them, because ad-blockers hide banner markup and external ad networks do the reporting, but they remain useful for partner logos.

Data model

Table Purpose

#__banners

One row per banner: cid (client), type (image or custom code), imptotal (impressions purchased, 0 for unlimited), impmade, clicks, clickurl, state, catid, sticky, ordering, custombannercode, params (image, size, alt), publish_up, publish_down, reset, plus per-banner purchase_type, track_impressions and track_clicks.

#__banner_clients

Advertisers: name, contact, email, extrainfo, state and the same three client-level tracking defaults.

#__banner_tracks

Hourly counters: track_date, track_type (1 for an impression and 2 for a click), banner_id and count.

The three tracking settings (purchase_type, track_impressions, track_clicks) are inherited: a banner value of -1 means "use the client’s", and a client value of -1 means "use the component option" under Banners > Options. This is why a surprising number can often be traced to the component option. The component options also contain track_robots_impressions (count robot traffic, default yes) and metakey_prefix. The purchase types are Unlimited, Yearly, Monthly, Weekly and Daily.

How a banner is chosen and counted

Selection happens in the site BannersModel. A banner is eligible when it is published, inside its publish window, its client (if any) is published, and either imptotal is 0 or impmade is below imptotal. The list is ordered by sticky descending, then by ordering, or randomly when the module’s ordering is random; the module can also filter by client, category, and tags matched against the page’s keywords (tag_search). Each time banners are shown, impmade is incremented, and, if impression tracking is enabled for that banner, the hourly row in #__banner_tracks is created or incremented.

Clicks go through the component: the module links to index.php?option=com_banners&task=click&id=<ID>, the DisplayController::click() task increments clicks (and the hourly track row of type 2), then redirects to the stored clickurl. The destination is therefore decided on the server and not by the visitor’s request.

flowchart LR A[Page renders mod_banners] --> B{Eligible banners} B -->|published, in window, client published, impmade below imptotal| C[Order by sticky then ordering or random] C --> D[Increment impmade] D --> E{Track impressions?} E -->|yes| F[Upsert banner_tracks type 1] A2[Visitor clicks] --> G[com_banners task click] G --> H[Increment clicks] H --> I{Track clicks?} I -->|yes| J[Upsert banner_tracks type 2] I --> K[Redirect to clickurl]

Screens

  • Components > Banners > Banners: list with state, client, impressions as made of purchased, clicks and click rate. The edit form has Details (type, image, width, height, alt, click URL, custom code), Banner Details (maximum impressions with Unlimited, total impressions and clicks with Reset impressions and Reset clicks buttons, client, purchase type, tracking), Publishing and meta key prefix options.

  • Clients: advertisers and their default tracking settings.

  • Tracks: the hourly statistics, filterable by client, category, type, and date range, with Export as CSV (optionally compressed as ZIP) and Delete Tracks, which deletes the rows matching the current filter and requires the core.delete permission.

  • Categories, plus ACL under Options > Permissions (see Users, groups, access levels and ACL).

  • The Banners module: count, client, category, tag search, ordering (including random), header and footer text and target window.

The Tallpine club sells two placements. Set the Alpine Outfitters client to "Weekly" purchase with 20,000 impressions purchased; the banner stops being offered once impmade reaches imptotal.

-- Weekly click-through report for one client (MySQL / MariaDB)
SELECT b.name,
       SUM(CASE WHEN t.track_type = 1 THEN t.count ELSE 0 END) AS impressions,
       SUM(CASE WHEN t.track_type = 2 THEN t.count ELSE 0 END) AS clicks
  FROM jos_banner_tracks AS t
  JOIN jos_banners       AS b ON b.id = t.banner_id
  JOIN jos_banner_clients AS c ON c.id = b.cid
 WHERE c.name = 'Alpine Outfitters'
   AND t.track_date >= NOW() - INTERVAL 7 DAY
 GROUP BY b.name;

Pitfalls and security

  • A banner of type Custom stores raw HTML or script in custombannercode; restrict who can create banners, because anyone with core.create can inject script into every page that shows the module.

  • Impressions are counted per render: with page caching or a CDN, a cached page shows the same banner and counts nothing new, so statistics are lower than traffic. Counting is also affected by the default of counting robots.

  • clickurl redirects: only trusted staff should set it, to avoid an open-redirect-style abuse of the tracking link.

  • Statistics are only as good as tracking: banners with tracking off produce an empty Tracks screen, which is not a bug.

  • Hourly rows grow without limit; export and delete old tracks regularly.

  • Rolling a weekly or monthly purchase period over (the reset column) is done from the banner; nothing in core resets counters automatically.

News Feeds

What it is

News Feeds stores references to external RSS or Atom feeds (#__newsfeeds) so the site can show their latest entries, either as a single feed page, a list of feeds in a category, or a module. It reads feeds; it does not publish them. The site’s own syndication is separate and is described below.

Fields and options

Per feed (forms/newsfeed.xml): name, alias, link (the feed URL), catid, published, access, language, numarticles (items to show, default 1 in the table and typically raised), cache_time (default 3600 seconds), rtl (right-to-left text), publish window, images and meta data. Display parameters, set per feed or globally in Options: show_feed_image, show_feed_description, show_item_description, feed_character_count (truncate item text), feed_display_order, float_first and float_second, show_tags, plus category and list options. The Integration tab has sef_ids.

The documented menu item types are Single News Feed and List News Feeds in a Category. The Feed Display module shows one feed anywhere, and its Word Count option limits each item, which keeps a sidebar tidy.

<!-- Seed record shape for the park-authority feed (illustrative values) -->
<newsfeed>
  <name>Park trail closures</name>
  <link>https://park-authority.example.org/closures.rss</link>
  <numarticles>5</numarticles>
  <cache_time>900</cache_time>
</newsfeed>

Internals and pitfalls

  • Fetched feeds are cached for cache_time seconds. A short value hits the park authority’s server on every page view once the cache expires; a long one delays closures. Joomla reads both RSS and Atom.

  • A feed that fails to load shows a message and never an error page; check the URL, TLS certificate and that the site’s server may make outbound HTTP requests.

  • Item text is external HTML. Treat the feed’s author as semi-trusted and keep show_item_description off unless you need it.

  • Item styling comes from the com-newsfeeds-newsfeed__items list class; the Guide suggests custom CSS in user.css (or a child template, see Child templates) to remove bullets and add spacing.

  • The Syndication Feeds module (mod_syndicate) is the opposite direction: it shows the link to the site’s own feed of the current Featured or Category Blog page. Whether the <link> tags appear is the RSS Feed Link option on Articles > Options > Integration (default Show), overridable per Category Blog menu item. Every Category Blog yields its own feed.

Weblinks (com_weblinks) was a core component up to Joomla 3 and was decoupled when Joomla 4 was released. It is maintained as the separate project joomla-extensions/weblinks and installed as a package from its GitHub releases (version 5.2.0 was published on 2026-10-16). It is not part of a clean install, and it is not in the User Guide’s component list. Before relying on it for a Joomla 6 site, read the compatibility statement of the release you intend to use and test it on the same stack, because extension updates in Joomla 6 respect the installed version’s declared target platform (see Installing and updating extensions). For many sites, a categorized list of links is more simply handled by articles, a custom field of type URL, or a Smart Search filter (Smart Search).

Corrections and version notes

  • Core Contacts, Banners and News Feeds work as in Joomla 4, but all three use the PSR-4 namespaces (for example Joomla\Component\Contact) and the Dispatcher/MVCFactory services; third-party overrides that call JFactory-style legacy classes need the Backward Compatibility plugin (BC6 in Joomla 6).

  • Contact plugin events are concrete event classes since 5.0; the old argument-order and by-reference forms are deprecated for removal in 7.0.

  • The reCAPTCHA plugin is no longer in core (removed in 5.0), which affects tutorials that tell you to enable it for the contact form; use another captcha plugin or the Proof-of-Work captcha from 6.1.

  • Older books and tutorials that use docs.joomla.org/J4.x or docs.joomla.org/J3.x links point to legacy wiki pages.