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:
The order of the zones is configurable — which is how a plugin makes its stylesheet win over the theme's.
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
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 inother— dropotherfrom the list as well;the theme declares it in
theme.xmlas a<library>, which lands inlibrary— 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
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