Developers
Assets
A plugin that renders a screen usually needs a stylesheet and a script. They
live beside the plugin's code and are pushed to the document by helpers named
css(), js(), and img() — available both on the plugin class and on a
plugin view, though the two are different methods with different third
arguments.
Most plugins need none of this. plg_bookings_notify renders a mail body and
nothing that reaches a browser, so it ships no assets directory at all. This
chapter is for the group tabs, member panels and project steps that do draw
something on a page — and its whole content is the answer to one question:
where does the framework look for the file, and what happens when it is not
there.
Where assets live
core/plugins/members/blog/
assets/
css/blog.css
img/
js/blog.js
The directory under assets matches the helper: css/, js/, img/. Files
placed directly under the plugin directory (blog/css/blog.css) are found
too, but every core plugin uses assets/.
Default names
Called with no arguments, the helpers work out both the extension and the file name for you:
- the extension defaults to
plg_{group}_{name}— for the members blog,plg_members_blog; - the file name defaults to the plugin's element, the third segment of that
string —
blog.
"Third segment" is literal: Hubzero\Document\Asset\File splits the
extension name on underscores and takes $parts[1] as the group directory and
$parts[2] as the element. A group or element name containing an underscore
resolves to a directory that does not exist, and by the rule at the end of this
chapter that means nothing loads and nothing complains. See
Characters in the two names.
So blog.css and blog.js are what $this->css()->js() loads, and
forum.css is what the groups forum plugin loads. Name your files after the
plugin and you never have to pass an argument.
On the plugin class
Hubzero\Plugin\Plugin mixes in the AssetAware trait:
| Method | Signature |
|---|---|
css |
css($stylesheet = '', $extension = null, $attributes = array()) |
js |
js($asset = '', $extension = null, $attributes = array()) |
img |
img($asset, $extension = null) |
css() and js() return $this, so they chain. The third argument is a
tag-attribute array: media, type, and attribs for a stylesheet; type,
defer, and async for a script.
$this->css()
->js('blog');
On a plugin view
Inside a layout, $this is a Hubzero\Plugin\View, and css(), js(), and
img() are resolved as view helpers
(Hubzero\View\Helper\Css and friends). Their signature differs:
| Method | Signature |
|---|---|
css |
css($stylesheet = '', $extension = null, $element = null) |
js |
js($asset = '', $extension = null, $element = null) |
img |
img($asset = '', $extension = null, $element = null) |
The third argument is not attributes: passing it makes the second and third be
read as a plugin group and element, and the pair is assembled into
plg_{group}_{element}. These two lines load the same file:
$this->css('like', 'plg_groups_forum');
$this->css('like', 'groups', 'forum');
Layouts in plg_groups_forum and plg_members_blog call these with one
argument or none:
$this->css()
->js();
$this->css('jquery.datepicker.css', 'system');
system resolves against the top-level core/assets directory, which is
where the shared jQuery plugins and icon sets live.
Where the file is looked for
Hubzero\Document\Asset\File builds this list for a plugin and takes the
first path that exists:
app/plugins/{group}/{name}/assets/css/file.css
app/plugins/{group}/{name}/css/file.css
core/plugins/{group}/{name}/assets/css/file.css
core/plugins/{group}/{name}/css/file.css
Every app/ path is tried before any core/ path, so a hub replaces a
shipped plugin's stylesheet by putting a file in app/plugins. A template can
override any of them with {template}/html/plg_{group}_{name}/file.css, which
is checked afterwards and wins.
The returned URL carries a cache-buster from the file's modification time:
/core/plugins/members/blog/assets/css/blog.css?v=1568392841.
Declarations
Passing css() a string containing { or @ makes it a declaration: the
string is added with addStyleDeclaration() rather than resolved to a path.
Useful for a rule computed from a parameter; not a way to build a stylesheet.
Images
img() returns a URL for a file under assets/img and keeps the extension
you give it:
<img src="<?php echo $this->img('icon.png'); ?>" alt="" />
Only png, gif, jpg, jpeg, and jpe are recognised. For an SVG, build
the path from Request::root(true) yourself.
Rewritten and checked against 2.4-main @ 91d03d0a23 on 2026-09-10.