Postinstall messages in Joomla
Right after you install Joomla, or just after a big update, you sometimes see a short message in the administrator: "We changed this setting, here is what you should know." It looks like a small notice, but it is a real core component doing a real job. That component is com_postinstall, and it is how Joomla and its extensions talk to you at the exact moment a change happens.
This article explains how the Joomla Post-installation Messages component really works. It covers the basics for website owners and editors, the day-to-day screen for administrators, and the technical details for developers: the message types, the states, the database table, the display pipeline, RAD paths, and how to create your own messages.
The quiet component that turns "we changed something important" into a message you can read, act on, and dismiss.
The goal is simple: help you understand com_postinstall well enough to read its messages with confidence and, if you build extensions, send your own.
1. The Basics
1.1 What com_postinstall Is
com_postinstall is a small core component that shows post-installation and upgrade messages. When Joomla itself, or one of your extensions, needs to tell you something right after an install or update, it stores a message and com_postinstall displays it. The official description is short and exact: "Displays post-installation and post-upgrade messages for Joomla and its extensions."
It is an administrator-only component. It has no frontend, no articles, and no public URL. It exists to deliver one-time notices to the people who run the site.
If you ever saw a Joomla notice like "Your old TinyMCE setting changed, click here to review it," that was com_postinstall.
1.2 Where to Find It
The screen lives under the System menu in the administrator:
System
└─ Manage
└─ Post-installation Messages
The full title of the page is Post-installation and Upgrade Messages. Its URL is index.php?option=com_postinstall in the administrator. You can also reach it from the System Dashboard, where a small notification panel shows how many messages wait for you.
1.3 Why It Exists
Some changes cannot be applied silently. A new Joomla version might add a security setting that you must turn on yourself, or change a default that affects your content. A normal email or changelog is easy to miss. A message that sits in the administrator, with a button that performs the change for you, is much harder to ignore. That is the whole point of com_postinstall: the right notice, in the right place, at the right time.
Back to top2. The Anatomy of a Message
Each message is shown as a card. A typical card has four parts:
| Part | What it is |
|---|---|
| Title | A short headline, shown as a heading on the card. |
| Since version | A small line, "Since version X", telling you which version introduced the message. |
| Description | The body text that explains the change and what you should do. |
| Action button | An optional button. It either opens a link or runs a task. Plain notices have no button. |
Next to the action button, administrators also see two small buttons to manage the message itself:
- Hide this message - removes the message from the list. You are done with it.
- Archive - moves the message to an "archived" state. It is no longer active, but you can read it again later.
Every text you read on the card comes from a language key, not from fixed text. The title, the description, and the button label are all keys like COM_FOOBAR_POSTINSTALL_MESSAGEONE_TITLE. Joomla loads the extension's language file and translates the key. This is why messages appear in your own language when a translation exists.
3. The Three Message Types
Every message has a type. The type decides whether there is a button and what the button does. There are exactly three types.
| Type | Button | What happens |
|---|---|---|
message |
None | A plain informative notice. You read it and dismiss it. |
link |
Yes | The button opens a URL, for example a settings page inside Joomla. |
action |
Yes | The button runs a PHP function that performs a change for you. |
3.1 message
The simplest type. There is no action button, only the title, the description, and the management buttons. Use it when you only need to inform.
3.2 link
The action button sends you to a URL. The URL is stored with the message. A common example is a button that opens a specific Options screen: index.php?option=com_foobar&view=tools&task=installSampleData. The user clicks, Joomla redirects, and the user finishes the change there.
3.3 action
The most powerful type. The button calls a PHP function inside the extension. Joomla loads a file, runs a named function, and the function does the work. This is how a message can say "Click here to fix this for you" and actually apply the fix when clicked.
Back to top4. Daily Use for Administrators
4.1 Reading and Clearing Messages
Open System → Manage → Post-installation Messages. Read each card. If a card has an action button, decide whether to use it. When you are finished with a message, click Hide this message. When the list is empty, Joomla shows a friendly note: "You have read all the messages."
4.2 The Extension Filter
At the top of the page there is a dropdown labelled Showing messages for. By default the list shows messages for the Joomla core (the "Joomla! files" extension). If other extensions have left messages, you can pick them from this dropdown to switch the list. When only the core has messages, the dropdown is hidden to keep the screen clean.
4.3 Hide All Messages
The toolbar has a Hide All Messages button. It hides every message for the currently selected extension in one click. Use it when you have read everything and want a clean dashboard.
4.4 Reset Messages
Hidden messages are not deleted, only marked as hidden. If you ever need them back, the empty-state screen offers a Reset Messages button. It re-enables every message for the selected extension, so they all return to the active list. This is useful when you hid a message too fast and want to read it again.
4.5 Read Again
An archived message is not gone either. On its card you will see a Read Again button (an archived message can be republished). Click it and the message returns to the active list. So you have two soft ways to remove a message (Hide and Archive) and two ways to bring messages back (Reset and Read Again).
Back to top5. Message States: Published, Hidden, Archived
Behind the buttons there is a single column, enabled, that holds the state of every message. It has three values.
| enabled | State | Meaning |
|---|---|---|
1 |
Published | Active. The message shows as a normal card with its action button. |
2 |
Archived | Set aside. Shown only as a small card with a "Read Again" button. |
0 |
Hidden | Dismissed. Not shown at all, but still stored in the database. |
The list screen loads messages where enabled is 1 or 2, so hidden messages (0) never appear. The notification count on the System Dashboard, however, counts only the 1 (published) messages, because those are the ones that still need your attention.
The buttons simply change this one value: Hide sets it to 0, Archive sets it to 2, Read Again and Reset set it back to 1.
6. Under the Hood: The Database Table
All messages live in one table, #__postinstall_messages. (The #__ prefix becomes your real table prefix, for example jos_postinstall_messages.) Each row is one message. These are the columns that matter.
| Column | Purpose |
|---|---|
postinstall_message_id |
Primary key, the unique id of the message. |
extension_id |
Which extension owns the message (a row in #__extensions). |
type |
One of message, link, or action. |
title_key |
Language key for the title. |
description_key |
Language key for the body text. |
action_key |
Language key for the button label (not used by message). |
language_extension |
Which extension holds the language keys, for example com_foobar. |
language_client_id |
Load frontend (0) or backend (1) language files. |
action_file |
RAD path to the PHP file for an action message. |
action |
For link: the URL. For action: the PHP function name. |
condition_file |
RAD path to a PHP file that decides if the message should show. |
condition_method |
The PHP function that returns true or false to show or hide the message. |
version_introduced |
The version that first showed this message ("Since version X"). |
enabled |
State: 1 published, 2 archived, 0 hidden. |
Notice that the table stores keys and paths, never the final text. The real words are resolved later from language files. This keeps messages translatable and small.
Back to top7. Under the Hood: How Messages Are Displayed
com_postinstall is a standard Model-View-Controller (MVC) component. When you open the screen, the flow is straightforward.
- The view asks the model (
MessagesModel) for the messages of the selected extension. - The model reads the rows from
#__postinstall_messageswhereenabledis1or2. - The model post-processes the list: it loads the right language files and runs each message's display condition.
- The template renders each surviving message as a card.
7.1 Conditions Decide Visibility
A message can carry a condition_file and a condition_method. During post-processing the model includes the file and calls the function. If the function returns false, the message is dropped from the list before it is ever shown. This is how a message can appear only when it is relevant, for example "only show this if the old setting is still active." Once the user fixes the problem, the condition returns false and the message quietly disappears.
7.2 Caching
The model caches its results in the com_postinstall cache group, because reading and evaluating messages on every page load would be wasteful. Whenever a message changes state (hide, archive, republish, reset), the component clears this cache so the list and the dashboard count stay correct.
7.3 Language Loading
Before rendering, the model loads each message's language extension, using the frontend or backend path based on language_client_id. This is why a message from com_foobar shows its own translated title and description, even though com_postinstall knows nothing about that extension's wording.
8. RAD Paths, Conditions, and Actions
8.1 What a RAD Path Is
The action_file and condition_file columns do not store full disk paths. They store short RAD paths with a prefix that Joomla expands at runtime. There are two prefixes.
| Prefix | Expands to | Example |
|---|---|---|
site:// |
The site root (JPATH_ROOT) |
site://components/com_foobar/postinstall.php |
admin:// |
The administrator folder (JPATH_ADMINISTRATOR) |
admin://components/com_foobar/postinstall.php |
A small helper expands the prefix into a real path before the file is included. Using a prefix keeps the stored value short and independent of where Joomla is installed.
8.2 Why Functions, Not Classes
Both the condition and the action point to plain PHP functions, not class methods. The model includes the file once and calls the function by name. A condition function must return true or false. An action function performs its work and returns nothing. Keep these functions simple and self-contained.
9. Creating Your Own Post-installation Messages
If you build extensions, you can add your own messages. The usual place is your extension's post-installation script, the script Joomla runs after your package is installed or updated. You call one method on the com_postinstall model and pass an array of options.
use Joomla\CMS\Factory;
$options = [
'extension_id' => $myExtensionId,
'type' => 'message',
'title_key' => 'COM_FOOBAR_POSTINSTALL_TITLE',
'description_key' => 'COM_FOOBAR_POSTINSTALL_DESCRIPTION',
'language_extension' => 'com_foobar',
'language_client_id' => 1,
'version_introduced' => '2.0.0',
'enabled' => 1,
];
Factory::getApplication()
->bootComponent('com_postinstall')
->getMVCFactory()
->createModel('Messages', 'Administrator', ['ignore_request' => true])
->addPostInstallationMessage($options);
The example above is a plain message: the simplest type and the one most likely to just work. The link and action types need a few more keys, described below.
9.1 The Required Options
The method validates your input and throws a clear exception when something is missing. The rules are:
extension_id,type,title_key,description_key, andlanguage_extensionare always required.typemust be exactlymessage,link, oraction.- For
linkandaction, you also need anaction_keyand acondition_filepluscondition_method. - For
link, setactionto the URL. Foraction, setaction_fileandaction(the function name), and the file must exist on disk.
9.2 Finding the extension_id
Every message needs the numeric extension_id of the extension that owns it. You can read it from the #__extensions table. For a component:
SELECT extension_id, name, type, element, client_id
FROM #__extensions
WHERE element = 'com_foobar';
For a plugin you must also match the folder, because the same element name can exist in different plugin groups:
SELECT extension_id, name, type, element, folder, client_id
FROM #__extensions
WHERE type = 'plugin'
AND folder = 'system'
AND element = 'foobar';
Inside an install or update script you do not need raw SQL: Joomla already knows your own extension id, so read it from the installer adapter instead of hard-coding a number.
9.3 Adding Is Safe to Repeat
The method checks for an existing row with the same extension, type, and title key. If the definition is identical, it does nothing. If it changed, it removes the old row and inserts the new one. This means you can call it on every update without creating duplicates, which is exactly what a post-installation script needs.
9.4 A Caveat With link Messages
Be careful with type = link when you register it through addPostInstallationMessage. In current Joomla 6 the method validates a link key, but that key is not part of the accepted option list and is stripped out before the check runs. The practical result is that a link definition can throw "needs an action (URL)" even when you supplied the URL in the action key as the documentation says.
Until this is resolved, the safe choices are: use message when you only need to inform, use action for a controlled internal task, and if you really need a link, test it on a clean install of the exact Joomla version you target and inspect MessagesModel::addPostInstallationMessage() first. A plain database row also works if you insert it yourself.
9.5 Security: action Messages Run PHP
An action message is powerful precisely because its button executes a PHP function from action_file. Treat that power with care.
- Keep the
action_fileinside your own extension. Never point it at user-supplied or remote content. - Inside the function, check the user's permissions before doing anything that changes data.
- Make the action idempotent, so clicking the button twice does no harm.
- Use the condition function only to return
trueorfalse. Never let it migrate data, write files, or change settings; conditions run often, including when Joomla counts messages. - Log important changes and fail gracefully, rather than trusting request input.
9.6 How This Differs From enqueueMessage()
Joomla has a second, more familiar way to show a message: Factory::getApplication()->enqueueMessage('Saved successfully.'). It looks similar but solves a different problem. Post-installation messages are durable; enqueued messages are not.
| Feature | enqueueMessage() | com_postinstall |
|---|---|---|
| Stored in the database | No | Yes |
| Survives a page reload | No | Yes |
| Can be dismissed permanently | No | Yes |
| Can include condition logic | No | Yes |
| Best for | Immediate, one-time feedback | Durable upgrade guidance |
Use enqueueMessage() for "your changes were saved" feedback during a single request. Use com_postinstall for guidance that must wait on the dashboard until the administrator acts on it.
10. Permissions and the Options Screen
com_postinstall uses Joomla's standard Access Control List (ACL). It defines a small set of actions.
| Action | Lets the user |
|---|---|
core.manage |
Open the component and read the messages. |
core.edit.state |
See and use the Hide, Archive, and Read Again buttons. |
core.admin |
Open the Options screen and edit permissions. |
So a user can be allowed to read messages without being allowed to change their state. The Options button in the toolbar appears only for users with core.admin, and the Options screen itself contains just the Permissions tab. There are almost no settings to tune here, which fits a component whose whole job is to relay messages from elsewhere.
11. Web Services API
Many Joomla core components ship a REST API under /api/index.php/v1/... so external tools can read or change data. com_postinstall is a deliberate exception: it has no Web Services API. There is no API controller, no public route, and no token-based endpoint for post-installation messages.
The reason is practical. These messages are short-lived, administrator-only notices that often run PHP actions or evaluate live conditions. Exposing them to remote clients would add risk without adding real value. If you need to read or clear them programmatically, you do it inside Joomla, through the same model method that the component itself uses, for example from a CLI plugin:
use Joomla\CMS\Factory;
$model = Factory::getApplication()
->bootComponent('com_postinstall')
->getMVCFactory()
->createModel('Messages', 'Administrator', ['ignore_request' => true]);
$count = $model->getItemsCount();
This keeps the logic, the conditions, and the cache handling consistent with the screen you see in the administrator.
Back to top12. SEO and Metadata
com_postinstall is a backend-only component, so it has no direct effect on SEO. It produces no frontend pages, no URLs that search engines can reach, and no metadata. Search engines never see a post-installation message.
The indirect effect, though, is real and worth saying. Many post-installation messages exist precisely to protect or improve your site: a new security header, a changed default that affects how content renders, a setting that influences performance. Acting on these messages keeps your site healthy, and a healthy, secure, fast site is the foundation of good SEO. So the rule is simple: read the messages, do what they ask when it makes sense, and your public site benefits even though the component itself stays invisible.
Back to top13. Common Mistakes and Pitfalls
13.1 Treating Messages as Spam
Symptom: You click "Hide All" without reading, every time.
Fix: Post-installation messages are rare and usually important. Read each one before hiding it. Many describe a security or behaviour change you genuinely need to know about.
13.2 Thinking Hidden Means Deleted
Symptom: You hid a message and now you cannot find it again.
Fix: Hidden messages are not deleted, only set to enabled = 0. Use the Reset Messages button on the empty-state screen to bring them all back, or Read Again for an archived one.
13.3 Looking at the Wrong Extension
Symptom: A message you expected is not in the list.
Fix: The screen filters by extension. By default it shows the Joomla core. Use the Showing messages for dropdown to switch to the extension that left the message.
13.4 Developer: Missing Condition File
Symptom: addPostInstallationMessage throws an exception during install.
Fix: For link and action types, the condition_file (and, for actions, the action_file) must exist on disk at the moment you register the message. Check your RAD path prefix (admin:// or site://) and that the file ships in your package.
13.5 Developer: Wrong Language Settings
Symptom: The card shows raw keys like COM_FOOBAR_POSTINSTALL_TITLE instead of text.
Fix: Set language_extension to the extension that owns the keys and language_client_id to the right side (1 for backend, 0 for frontend), and make sure the language file is installed.
13.6 Developer: link Message Throws on Registration
Symptom: Registering a type = link message with addPostInstallationMessage throws "needs an action (URL)", even though you set the URL.
Fix: This is a known validation quirk in current Joomla 6, where the method checks a link key that it has already stripped from the options. Use message or action instead, or insert the row directly, and test link messages on the exact Joomla version you target. See section 9.4.
14. Best Practices
If you remember only a few things from this article, remember these:
- Check
System → Manage → Post-installation Messagesafter every Joomla or extension update. - Read each message before you hide it. They are infrequent and usually matter.
- Use Archive for messages you want to keep for later, and Hide for those you are truly done with.
- Remember that nothing is deleted: Reset Messages and Read Again bring messages back.
- As a developer, register messages from your post-installation script so they survive updates without duplicating.
- Use conditions so a message appears only while it is relevant, and disappears once the user acts.
- Always use language keys, never hard-coded text, so your messages stay translatable.
15. Quick Reference
SCREEN
System > Manage > Post-installation Messages
URL: index.php?option=com_postinstall
MESSAGE TYPES
message informative only, no button
link button opens a URL
action button runs a PHP function
STATES (enabled column)
1 published shown as active card
2 archived shown with "Read Again"
0 hidden stored but not shown
BUTTONS
Hide this message enabled -> 0
Archive enabled -> 2
Read Again enabled -> 1 (from archived)
Hide All Messages all of one extension -> 0
Reset Messages all of one extension -> 1
DATABASE
#__postinstall_messages one row per message
RAD PATH PREFIXES
site:// -> site root (JPATH_ROOT)
admin:// -> administrator (JPATH_ADMINISTRATOR)
DEVELOPER API
bootComponent('com_postinstall')
->getMVCFactory()
->createModel('Messages', 'Administrator', ['ignore_request' => true])
->addPostInstallationMessage($options);
PERMISSIONS
core.manage open and read
core.edit.state hide / archive / republish
core.admin Options screen
WEB SERVICES API
none (no REST endpoint)
Back to top16. Summary
com_postinstall is a small but useful piece of Joomla. Here is what to keep in mind:
- It shows post-installation and upgrade messages from Joomla and its extensions, in the administrator only.
- Messages come in three types: a plain notice, a link, or a PHP action.
- The
enabledcolumn gives each message a state: published, archived, or hidden. Nothing is ever deleted. - All messages live in
#__postinstall_messagesand store language keys and RAD paths, not final text. - The model loads, conditions, caches, and translates the messages before the template renders them as cards.
- Developers register messages from a post-installation script with
addPostInstallationMessage, safely and repeatably. - There is no Web Services API; the component is meant for the people who run the site.
Most of the time you only glance at this screen, hide a message, and move on. But when a post-installation message appears after an update, it is often the clearest warning you will get that something on your site needs attention. If your Joomla site has a stack of unread messages, or you are not sure whether a past update left a setting half-changed, it pays to have someone read them with you and check the underlying configuration. That is exactly the kind of quiet, careful Joomla maintenance work I enjoy.
Back to top

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


