For the complete documentation index, see llms.txt. This page is also available as Markdown.

Rendering a plugin page without the site theme's CSS

Applies to: e107 v2.3+ Verified against: e107_core/templates/header_default.php, e107_handlers/js_manager.php

The problem

You have a plugin page that ships its own front-end framework — an admin-like dashboard, a member area, a booking screen — and it has to look the same on every site that installs the plugin.

e_IFRAME gets you part of the way: it suppresses the theme's HEADER and FOOTER markup, so your page is no longer wrapped in the site's layout. But the page still loads every stylesheet the theme registered, because e107 builds one <head> for the whole request and has no notion of "this page is not themed".

The result is a page that looks right on one theme and broken on the next: your framework and the theme's Bootstrap both style .table, .btn and .card, and which one wins depends on the theme the site happens to run.

Writing CSS overrides against that is a losing game. You cannot know which theme you are fighting, and every override you add to win one argument breaks a different site.


The mechanism

CSS is not emitted file by file. e107 sorts every registered stylesheet into one of six zones, and header_default.php renders the zones in the order named by the CSSORDER constant:

// e107_core/templates/header_default.php
$CSSORDER = deftrue('CSSORDER')
    ? explode(",", CSSORDER)
    : array('library', 'other', 'core', 'plugin', 'theme', 'inline');

foreach($CSSORDER as $val)
{
    $cssId = $val . "_css";
    $e_js->renderJs($cssId, false, 'css');
}

Two things follow from those seven lines, and the second one is the useful one:

  1. The order of the zones is configurable — which is how a plugin makes its stylesheet win over the theme's.

  2. A zone that is not in the list is never rendered at all.

Nothing else reads CSSORDER. Leaving a zone out does not disable the API that fills it; the files are still registered; they are simply never written to the page.

The zones, and what puts a file in each

Zone
Filled by
Typically holds

library

$e_js->registerLibrary(), theme <libraries>

jQuery UI, Bootstrap, framework CSS declared by the theme

other

e107::css('url', ...), $e_js->otherCSS()

CDN links, preview theme, backward-compatibility files

core

$e_js->coreCSS()

e107.css — the admin bar, message boxes

plugin

e107::css('myplugin', ...), $e_js->pluginCSS()

your plugin's stylesheets

theme

$e_js->themeCSS(), THEME_STYLE

the site theme's style.css and anything it registers

inline

$e_js->inlineCSS()

<style> blocks


The fix

Define CSSORDER in your plugin's front controller, before anything renders, and leave out the zones you do not want:

e107::css('myplugin', 'assets/css/mystyle.css') puts your file in the plugin zone, which is still listed, so it renders as usual.

Where the definition has to sit

CSSORDER is read while header_default.php builds the <head>, so it must be defined before HEADERF is required. Anywhere after class2.php and before the header is fine. Defined later, it is simply ignored — and the symptom is a page that looks exactly as if you had never touched it.

Dropping core CSS as well

e107.css is in the core zone, but it has its own switch rather than being dropped from CSSORDER — it is registered conditionally:

So:

Think twice about this one. e107.css styles the admin bar and e107's message boxes; without it a logged-in administrator loses the bar and your {ALERTS} come out unstyled.


Use it with e_IFRAME, not instead of it

The two solve different halves of the same problem, and you normally want both:

e_IFRAME also adds class='e-iframe' to the body and lets the theme opt back in through e_IFRAME_HEADER / e_IFRAME_FOOTER, so a theme that wants to wrap iframe pages still can.


Checking it worked

View source and look at the <link rel="stylesheet"> tags. You should see your plugin's files and nothing from e107_themes/.

If a theme stylesheet is still there, it was not in the theme zone. The two usual reasons:

  • the theme registers its CSS with $e_js->otherCSS() or a CDN URL, which lands in other — drop other from the list as well;

  • the theme declares it in theme.xml as a <library>, which lands in library — that zone is already out of the example above.

Work from the rendered <head>: the order of the tags mirrors the order of the zones, so you can tell which zone a file came from by where it appears.


Why not just override the CSS

Because an override cannot know what it is overriding.

The specific trap: a framework like Tabler and the theme's Bootstrap both style through CSS custom properties. Load order settles a conflict between two rules setting the same property, but a variable set by the theme keeps applying no matter which stylesheet wins the rule — background-image from the theme survives a later background-color from your framework, because they are different properties.

Not rendering the theme's CSS removes the argument instead of trying to win it, and it is the only approach that behaves the same on a theme you have never seen.


Summary

Goal
Line

No theme stylesheets

define('CSSORDER', 'other,core,plugin,inline');

Also no e107.css

define('CORE_CSS', false);

No theme HEADER/FOOTER markup

define('e_IFRAME', true);

Your CSS last (keeping the theme)

define('CSSORDER', 'library,other,core,theme,plugin,inline');

All of them must be defined before HEADERF is required.

Last updated