Skip to main content

Wrapper in Joomla

27 June 2026

Sometimes you do not want to rebuild another website inside Joomla. You just want to show it: a booking calendar, a legacy PHP tool, a map, a form hosted somewhere else. Joomla has a small, often forgotten core component for exactly this job: the Wrapper.

The Wrapper component (com_wrapper) does one thing. It places an <iframe> on a Joomla page and points it at a URL. The external page loads inside a frame on your site, framed by your template's header, footer, and menu. There is no content to write, no record to store, just a URL and a few display settings.

Joomla's one-trick component: wrap any external page in an iframe, straight from a menu item.

This article explains how the Wrapper really works. It covers the basics for website owners, the setup for administrators, and the technical details for developers. You will learn how to create a wrapper, how Joomla rewrites the URL, why "auto height" often fails, how the mod_wrapper module differs, and the security rules that decide whether the external page will load at all.

1. The Basics

1.1 What a Wrapper Is

A Wrapper is an <iframe> with a Joomla menu item in front of it. When a visitor clicks the menu link, Joomla renders a normal page with your template, and inside the content area it drops a single frame that loads another web address.

Think of it as a window. Your template is the wall. The iframe is the window. Through the window you see a completely separate web page, served by another script or another server entirely.

The Wrapper does not copy, import, or store the external page. It only tells the browser: "load this other URL inside this box."

1.2 What Makes It Unusual

Almost every core Joomla component stores something: articles, contacts, banners, feeds. The Wrapper stores nothing. It has:

  • No database table of its own.
  • No categories.
  • No custom fields.
  • No back-end management screen where you create "wrapper records".
  • No Web Services (REST) API.

Everything a wrapper needs - the URL, the width, the height - lives in the menu item parameters. The menu item is the wrapper. Delete the menu item and the wrapper is gone.

1.3 Where to Find It

You will not find a "Wrapper" entry under the Components menu, because there is nothing to manage there. You create a wrapper as a menu item type:

Menus → (your menu) → New → Iframe Wrapper

In the menu item type chooser it appears under Wrapper as Iframe Wrapper. That single layout is the whole front end of the component.

Back to top

2. Creating a Wrapper Menu Item

2.1 The Steps

Creating a wrapper takes less than a minute:

  1. Go to Menus → (your menu) → New.
  2. Set Menu Item Type to Wrapper → Iframe Wrapper.
  3. Enter a Menu Title (this becomes the page title and the link text).
  4. In the URL field, type the address you want to wrap, for example https://example.com/tool.
  5. Save.

That is all that is strictly required. The remaining options control size, scaling, and loading behaviour.

2.2 The Required Field: URL

The only required setting is the URL. In the menu item it sits in the Basic fieldset and is defined like this:

<field name="url" type="url" validate="url"
       filter="url" relative="true" required="true" />

Because relative="true", Joomla accepts both absolute addresses (https://example.com/page) and addresses relative to your own site (/some/local/page). How Joomla turns what you type into the final src attribute is covered in section 4.

Back to top

3. The Wrapper Options Explained

A wrapper menu item exposes a small, fixed set of parameters. They are grouped into three fieldsets in tmpl/wrapper/default.xml.

3.1 Basic (Scroll Bar Parameters)

OptionParamDefaultWhat it does
Width width 100% The iframe width. A percentage scales with the page; a number is treated as pixels.
Height height 500 The iframe height in pixels. A frame has no natural height, so you must set one.

3.2 Advanced

OptionParamDefaultWhat it does
Auto Height height_auto 0 (No) Tries to resize the frame to fit its content using JavaScript (see section 5).
Auto Add add_scheme 1 (Yes) Adds a scheme (http:// or https://) to the URL if you did not type one.
Lazy Loading lazyloading lazy Sets the iframe loading attribute. lazy defers the frame until it is near the viewport; eager loads it immediately.

Note one naming quirk: the label is Auto Add, but the stored parameter is add_scheme. The description in the back end explains it well: "By default, http:// will be added unless it detects http:// or https:// in the URL you provide."

3.3 Page Display (Inherited)

Like every menu item, a wrapper also has the standard Page Display tab: Browser Page Title, Show Page Heading, and Page Heading. The layout uses these to print an optional <h1> above the frame and to set the iframe's title attribute - which matters for accessibility.

Back to top

4. How the URL Is Processed

This is the part most people never see, and it explains several "why did my link change?" surprises. When Auto Add (add_scheme) is on - the default - the view rewrites the URL before printing it.

4.1 The Four Cases

The logic lives in the front-end view (HtmlView.php) and works through the URL you typed in order:

What you typedWhat Joomla doesResult
//example.com/x Prepends the current scheme. https://example.com/x
/local/page Prepends scheme + host + port (your own site). https://yoursite.test/local/page
example.com/x (no scheme) Prepends the current scheme. https://example.com/x
https://example.com/x Leaves it unchanged. https://example.com/x

"Current scheme" means whatever your Joomla page is using right now, usually https://. This is why a wrapped URL almost always ends up on HTTPS when your own site runs on HTTPS.

4.2 When to Turn Auto Add Off

Switch Auto Add to No when you need the URL passed through exactly as typed - for example a non-standard scheme, or a URL where automatic scheme handling gets in the way. With it off, the view uses your value verbatim.

// HtmlView.php (simplified)
if ($params->def('add_scheme', 1)) {
    // four-case rewrite above
} else {
    $wrapper->url = $url;   // use exactly what was typed
}
Back to top

5. Auto Height and the iFrame Script

An iframe does not grow to fit its content the way a normal <div> does. You give it a fixed height, and anything taller scrolls inside the frame. Auto Height is Joomla's attempt to fix that.

5.1 How It Works

When height_auto is on, the view adds an onload handler to the iframe:

<iframe onload="iFrameHeight(this)" ... >

The handler ships in the component's own script, media/com_wrapper/js/iframe-height.js. In plain terms it does this:

1. When the frame finishes loading, read the inner page.
2. Measure document.body.scrollHeight.
3. Set the iframe height to that value + 60px (a small buffer).

The result is a frame that is tall enough to show the wrapped page without an inner scrollbar.

5.2 The Big Catch: Same-Origin Only

Reading iframe.contentDocument.body.scrollHeight means reaching inside the framed page. Browsers only allow that when the framed page is on the same origin (same scheme, host, and port) as your Joomla site.

So Auto Height works only when you wrap a page on your own domain. Point it at a different domain and the browser's same-origin policy blocks the measurement. The script fails silently and the frame keeps its fixed height.

Rule of thumb: Auto Height is for wrapping your own legacy pages. For third-party sites, set a sensible fixed height instead.
Back to top

6. The Module Alternative: mod_wrapper

The component puts an iframe on its own page through a menu item. The core Wrapper module (mod_wrapper) puts the same kind of iframe into a module position - a sidebar, a footer, anywhere a position exists - on top of other content.

Content → Site Modules → New → Wrapper   (mod_wrapper)

6.1 Component vs Module

 com_wrappermod_wrapper
Where it appears Its own page (menu item) Any module position
Needs a menu item Yes No
Height default 500 200
Auto Height default Off On
Frame target/name Fixed (iframe) target field you can set
Module caching n/a Yes (static cache, default 900s)
Best for A full page that wraps an external tool A small framed widget beside your content

6.2 Shared Code

Both use the very same JavaScript asset, com_wrapper.iframe (iframe-height.min.js). The component and the module are two front ends over one idea: render an <iframe>. Use the component when the wrapped page is the page; use the module when it sits alongside your real content.

Back to top

7. Under the Hood (Developer View)

7.1 No Table, No Model Data

There is no #__wrapper table. The component reads everything from the active menu item's parameters:

$params = Factory::getApplication()->getParams();
$url    = $params->def('url', '');

That is the entire data source. The "model" has nothing to load, because the page you see lives on another server.

7.2 Where the Settings Actually Live

"No table of its own" does not mean "stored nowhere". A wrapper relies on two shared core tables:

TableWhat it holds for the Wrapper
#__menu The wrapper menu item itself. The params column stores the URL, width, height, and the other options as JSON.
#__extensions The registration of the com_wrapper component (its namespace, manifest cache, and enabled state).

So the configuration you set in the menu item ends up as a JSON string in #__menu.params:

SELECT id, title, params
FROM #__menu
WHERE link LIKE '%com_wrapper%';

-- params (decoded):
-- {"url":"https://example.com","width":"100%","height":"500",
--  "height_auto":"0","add_scheme":"1","lazyloading":"lazy"}

Joomla loads that JSON into a Registry object, which is exactly what $params->get('url') reads in the view. This is why deleting the menu item deletes the wrapper: the menu row is the storage.

7.3 The MVC Layout

The component is one of the smallest in Joomla:

administrator/components/com_wrapper/      ← registers the component + router
   src/Extension/WrapperComponent.php
   services/provider.php

components/com_wrapper/                     ← the entire front end
   src/Controller/DisplayController.php     forces caching, sets view
   src/View/Wrapper/HtmlView.php            builds the URL + params
   src/Service/Router.php                   trivial SEF routing
   tmpl/wrapper/default.php                 prints the <iframe>
   tmpl/wrapper/default.xml                 the menu item options

There is an administrator side, but it exists only to register the component and its router so the menu item type is available. It has no management view.

7.4 The Controller Forces Caching

The display controller hard-codes caching on:

public function display($cachable = false, $urlparams = [])
{
    $cachable = true;   // always cache
    $vName    = $this->input->get('view', 'wrapper');
    $this->input->set('view', $vName);

    return parent::display($cachable, ['Itemid' => 'INT']);
}

This is cheap and safe: the output is just an <iframe> tag, identical for every visitor of that menu item. The expensive part - loading the framed page - happens in the visitor's browser, not on your server, so there is nothing heavy to cache anyway.

7.5 The Router Is Almost Empty

Because there is only one view and no records, the router barely does anything:

public function build(&$query) {
    unset($query['view']);   // nothing to encode
    return [];
}
public function parse(&$segments) {
    return ['view' => 'wrapper'];   // always the same view
}

In practice the SEF URL is simply the menu item alias. There are no ids, slugs, or extra segments to route.

7.6 What the Template Prints

The layout output is short. Stripped of the heading block, it is essentially:

<div class="com-wrapper contentpane">
  <iframe id="blockrandom" name="iframe"
          src="/(the processed URL)"
          width="(width)" height="(height)"
          loading="(lazy|eager)"
          title="(page heading or title)"
          class="com-wrapper__iframe wrapper">
    This option will not work correctly. Unfortunately, your
    browser does not support inline frames.
  </iframe>
</div>

The text inside the iframe is the fallback for browsers that cannot render frames - practically none today, but it is valid HTML to provide it.

7.7 Template Overrides

You can override the layout like any other view:

components/com_wrapper/tmpl/wrapper/default.php
templates/<your_template>/html/com_wrapper/wrapper/default.php   ← override

This is the right place to add a wrapping element, extra ARIA attributes, a responsive aspect-ratio box, or a sandbox attribute on the iframe (see section 8).

Back to top

8. Security: iframes and the Outside World

The Wrapper is simple to use but it touches one of the web's trickiest areas: embedding one site inside another. Most "the wrapper is blank" problems are security features doing their job.

8.1 The Other Site Decides If It Can Be Framed

You can point a wrapper anywhere, but the target site controls whether browsers may frame it. Two response headers do this:

HeaderEffect when set by the target
X-Frame-Options: DENY / SAMEORIGIN The browser refuses to display the page in your frame.
Content-Security-Policy: frame-ancestors ... The modern equivalent; lists exactly who may frame the page.

Big sites (Google, most banks, many SaaS apps) send these on purpose to prevent clickjacking. If a wrapper shows a blank or refused frame, this is almost always why - and there is nothing you can change on the Joomla side to override it.

8.2 Mixed Content

If your Joomla site runs on HTTPS and you wrap an http:// URL, the browser blocks the insecure frame as mixed content. Always wrap HTTPS targets. (Auto Add's scheme handling usually pushes you to HTTPS anyway, as shown in section 4.)

8.3 Cookies and Logins Inside a Frame

This is the trap that catches people who wrap an application that needs a login. When the framed app sits on a different domain from your Joomla site, its session cookie is a third-party cookie, and modern browsers restrict those heavily.

The deciding factor is the cookie's SameSite attribute on the target app:

Cookie settingBehaviour inside your frame
SameSite=Lax / Strict The cookie is not sent in the framed (cross-site) request, so the app never sees the session.
SameSite=None; Secure The cookie can be sent, but only over HTTPS - and browsers are increasingly partitioning or blocking these too.

The usual symptoms are a login loop (the app keeps asking you to sign in), lost sessions, or authentication that works in a normal tab but not in the frame. There is no Joomla setting that fixes this: the cookie rules belong to the target app and the browser. The wrapped app must send SameSite=None; Secure (and often opt into storage access) for in-frame logins to work, or you keep the wrapped app on your own domain.

8.4 Clickjacking - the Other Direction

Framing cuts both ways. If your site can be framed by anyone, an attacker could overlay it to trick users. Protect your own pages by sending X-Frame-Options or a frame-ancestors policy. Joomla's HTTP Headers plugin can set both.

8.5 Hardening the Frame You Embed

When you wrap third-party content, treat it as untrusted. In a template override you can add a sandbox attribute to limit what the framed page may do:

<iframe ... sandbox="allow-scripts allow-same-origin">

Add only the capabilities the embedded tool genuinely needs. Restrict who can create or edit wrapper menu items too, since a menu item is the only thing standing between a URL and your visitors' browsers.

Back to top

9. SEO and Metadata

A wrapper page is one of the weakest pages you can publish for search, and it helps to understand why.

  • Search engines do not index framed content as yours. The text inside the iframe belongs to the other URL. Google credits it to that site, not to your wrapper page.
  • Your wrapper page has almost no text of its own - just an optional heading and a frame. There is little for a crawler to rank.
  • The view still sets metadata. The Browser Page Title, meta description, and robots from the menu item's Metadata tab are applied, so you can at least control the title and noindex if needed.

If a page matters for SEO, do not wrap it - rebuild that content as a real Joomla article. Reserve the Wrapper for tools and utilities where ranking is irrelevant: dashboards, calculators, booking widgets, internal apps.

Back to top

10. Common Mistakes and Pitfalls

10.1 "The Frame Is Blank or Says Refused to Connect"

Symptom: The page loads, your template shows, but the frame is empty or shows a browser refusal message.

Fix: The target site sends X-Frame-Options or a frame-ancestors policy that forbids framing. Check the target's response headers. You cannot bypass this; either the site must allow your domain, or you cannot wrap it.

10.2 "Auto Height Does Nothing"

Symptom: You enabled Auto Height, but the frame keeps a fixed size and scrolls internally.

Fix: Auto Height only works for same-origin pages (section 5). For an external domain the browser blocks the height measurement. Set a sensible fixed height instead.

10.3 "The Frame Has No Height at All"

Symptom: The wrapped page is invisible or only a sliver high.

Fix: An iframe needs an explicit height. Confirm the height value (default 500) is set and is a number of pixels. 100% height does not work without a sized parent.

10.4 "Mixed Content Warning"

Symptom: An HTTPS site wraps an HTTP URL and the frame is blocked.

Fix: Use the https:// version of the target URL. Leave Auto Add on so the current (secure) scheme is applied.

10.5 "The Wrapped App Keeps Asking Me to Log In"

Symptom: You wrap an external application that needs a login, and it loops back to the login screen, or the session drops, even though it works fine in its own tab.

Fix: This is the third-party cookie / SameSite restriction from section 8.3, not a Joomla bug. The framed app must set its session cookie with SameSite=None; Secure for the browser to send it inside your frame. If you cannot change the app, host it on your own domain or link to it in a new tab instead of wrapping it.

10.6 "My URL Changed After I Saved"

Symptom: You typed example.com/x and the frame loads https://example.com/x.

Fix: That is Auto Add (add_scheme) prepending the scheme. This is normal. Turn Auto Add off only if you truly need the URL untouched.

10.7 "I Wrapped a Page for SEO"

Symptom: You expected the framed content to boost your rankings.

Fix: It will not. Framed content is not yours in a crawler's eyes. Publish real articles for anything that needs to rank (section 9).

Back to top

11. Best Practices

If you only remember a few things from this article, remember these:

  • Use the Wrapper for tools and external apps, never for content that must rank in search.
  • Always wrap HTTPS URLs to avoid mixed-content blocking.
  • Expect Auto Height to work only for pages on your own domain; otherwise set a fixed height.
  • Before wrapping a site, check that it does not forbid framing with X-Frame-Options or frame-ancestors.
  • Set a clear Page Heading - it becomes the iframe's accessible title.
  • For untrusted targets, add a sandbox attribute via a template override.
  • If the wrapped app needs a login, expect cross-domain cookie problems unless it sets SameSite=None; Secure.
  • Pick the right tool: a full page uses com_wrapper; a sidebar widget uses mod_wrapper.
Back to top

12. Quick Reference

CREATE       Menus → New → Wrapper → Iframe Wrapper
URL          url          (required; relative or absolute)
WIDTH        width        default 100%  (% scales, number = px)
HEIGHT       height       default 500   (pixels; required to be visible)
AUTO HEIGHT  height_auto  default 0 (Off); SAME-ORIGIN ONLY
AUTO ADD     add_scheme   default 1 (On); prepends http(s):// scheme
LAZY LOAD    lazyloading  default lazy  (lazy | eager)
SCRIPT       media/com_wrapper/js/iframe-height.js  (+60px buffer)
TABLE        none of its own  (params in #__menu.params; reg in #__extensions)
LOGINS       cross-domain apps need SameSite=None; Secure cookies
ROUTER       src/Service/Router.php  (always view=wrapper)
CACHE        controller forces $cachable = true
OVERRIDE     templates/<tpl>/html/com_wrapper/wrapper/default.php
MODULE       mod_wrapper  (same iframe, in a module position)
BLOCKED BY   target's X-Frame-Options / CSP frame-ancestors
API          none         (no Web Services / REST endpoints)
Back to top

13. Summary

The Wrapper is the smallest core component in Joomla, and it does exactly one thing: it puts an <iframe> on a page and points it at a URL.

What makes it worth understanding:

  • No storage: there is no table, no record, no category. The menu item parameters are the whole configuration.
  • URL rewriting: Auto Add quietly normalises your URL and usually forces the current scheme.
  • Auto Height: a handy JavaScript resize that only works for same-origin pages.
  • Two front ends: com_wrapper for a full page, mod_wrapper for a module position, sharing one script.
  • Security first: whether a frame loads at all is decided by the target site's framing headers, not by Joomla.
  • Weak for SEO: framed content is never counted as your own.

Once you see that the Wrapper stores nothing and simply hands a URL to the browser, every quirk - the rewritten scheme, the silent Auto Height failure, the blank "refused to connect" frame - makes sense.

If you are wrapping a legacy tool, an external booking system, or an internal app and the frame will not behave, these framing headers and same-origin rules are usually the cause. When a wrapper turns into a stubborn integration problem, it often pays to look at how the two sites are allowed to talk to each other before blaming Joomla.

Back to top
Wrapper in Joomla
Peter Martin
Peter Martin
Joomla Specialist

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