I'm trying to remove unwanted scripts from my custom joomla template header, which I've managed to remove everything except for this:
<script type="text/javascript">
jQuery(document).ready(function()
{
jQuery('.hasTooltip').tooltip({});
});
</script>
I've searched for hours and I've tried numerous things to get it removed, but I can't seem to get rid of it. Here's what I've done to remove the other scripts I don't want (for anyone else who has this issue):
# unset frameworks
JHtml::_('bootstrap.framework',false);
JHtml::_('jquery.framework',false);
# unset scripts
unset($doc->_scripts[$this->baseurl.'/media/jui/js/jquery.min.js']);
unset($doc->_scripts[$this->baseurl.'/media/jui/js/jquery-noconflict.js']);
unset($doc->_scripts[$this->baseurl.'/media/jui/js/bootstrap.min.js']);
If someone could help me remove that tooltip javascript, that would be fantastic. Oh and I don't want to touch the core files, so I'm trying to remove it from the template index.php file itself.
Some component/Module/Plugin is calling the function JHTML::_('behavior.tooltip'). and that function add your code.
you can do:
The dirty way: go to libraries\cms\html\bootstrap.php and change the file at the method tooltip(). but remember it's a core file so upgrade can overide your changes.
The clean way, find the component that adds this code and remove or change it.
Good Luck
You'll have to manually parse $doc->_script. The $doc->_scripts array contains scripts that are linked to another source while $doc->_script is for script declarations like the tooltip one.
I managed to get rid of the embedded javascript using this code in my template's index.php file:
unset($this->_script['text/javascript']);
disclaimer: I am not a PHP developer, so use above code at your own risk :)
At the end of your web root index.php (not template, http://domain.com/index.php) replace the $app->execute(); line with the following:
// Start the output buffer.
ob_start();
// Execute the application.
$app->execute();
// Get buffer
$buffer = ob_get_clean();
// Change HTML
$buffer = str_replace('<script type="text/javascript">'.chr(10).'jQuery(document).ready(function(){'.chr(10).' jQuery(\'.hasTooltip\').tooltip({"html": true,"container": "body"});'.chr(10).'});'.chr(10).' </script>','',$buffer);
// Output buffer
echo($buffer);
Note that you would need to use the EXACT HTML that's being created by the module. This is what my module is creating, yours could be slightly different.
In addition to doing HTML rewrites like this, you could also tidy the output, remove links to modules, etc.
I also use this for doing things like changing the copyright year on a website. In a module position, I reference the current year as "{year}" and then I add another str_replace which does the following:
$buffer = str_replace('{year}',date('Y'),$buffer);
Bingo, always shows the current year.
Enjoy...
Based on Joomla documents, 2 things to consider:
a) In the below code, you're actually enabling/including bootstrap and jquery:
# unset frameworks
JHtml::_('bootstrap.framework',false);// including bootstrap!
JHtml::_('jquery.framework',false);// including jquery!
When bootstrap is enabled, joomla automatically enables jquery, and if joomla enabled jquery, joomla automatically enables tooltip.
Just don't call these functions. The unset you used will remove bootstrap and jquery correctly:
unset($doc->_scripts[$this->baseurl.'/media/jui/js/jquery.min.js']);
unset($doc->_scripts[$this->baseurl.'/media/jui/js/jquery-noconflict.js']);
unset($doc->_scripts[$this->baseurl.'/media/jui/js/bootstrap.min.js']);
unset($doc->_scripts[$this->baseurl.'/media/jui/js/jquery-migrate.min.js']);
b) if the tooltip script is still included, it's probably inserted by JHtml::_('behavior.tooltip'); somewhere in the used component.
Lastly, never never never modify Joomla core files. it's a worst-practice.
PS.
For those who mentioned that the tooltip script is inserted but they don't find it in the $doc, that's because the $doc doesn't contain inline scripts.
I have already meet this issue, I am using Joomla 3. If it is your case then you can solve it by doing this :
Joomla 3 comes with jQuery on board, so by adding Joomla yourself, this may generate the issue.
Also make sure you include your jQuery over <jdoc:include type="head" />. If you necessary wants to include it. But I do not recommend this.
Hope this helps
I had the same problem when I was building a Joomla template/site with only HTML5, CSS3 and some small jQuery plugins for effects. It was unworthy of including heavy Bootstrap just to show some tooltips which I also didn't use at all.
Althought I already unset media/jui/js/bootstrap.min.js from JDocument but these lines of code
jQuery(document).ready(function(){
jQuery('.hasTooltip').tooltip({"html": true,"container": "body"});
});
were still appended by libraries/cms/html/bootstrap.php. So I got error "function tooltip not found".
I solved that by adding an empty function to my template's JS file.
jQuery.fn.tooltip = function (option) { };
There's a Joomla Plugin available which unsets Bootstrap and also removes the tooltip function snippet wich is inserted by JHtml::_('behavior.tooltip'); somewhere in any component.
See here: Disable Bootstrap Plugin
Create a system plugin with the follow code.
The First foreach loop unsets the .js file(s) added to the head. And the next foreach loop unsets the js code injected inside <script> tags.
There are two separate properties containing the scripts the _script & _scripts
public function onBeforeCompileHead() {
// Front end
if ($this->app instanceof JApplicationSite) {
$doc = JFactory::getDocument();
$search = array(
// 'jquery',
// 'caption.js',
// 'bootstrap.min.js',
// 'core.js',
// 'keepalive.js',
// 'punycode.js',
// 'validate.js',
// 'calendar.js',
// 'calendar-setup.js',
// 'mootools-more.js',
// 'modal.js',
// 'ajax-chosen.min.js',
// 'tabs-state.js',
// 'frontediting.js',
// 'html5fallback.js',
// 'jui/js/bootstrap.min.js',
// 'jquery.min.js',
'jui/js/',
'system/js/',
// 'text/javascript'
);
foreach ($doc->_scripts as $key => $script) {
foreach ($search as $findme) {
if (stristr($key, $findme) !== false) {
unset($doc->_scripts[$key]);
}
}
}
foreach ($doc->_script as $key => $script) {
if (stristr($key, 'text/javascript') !== false) {
unset($doc->_script[$key]);
}
}
}
}
Related
I am trying to make some changes to PHP files in Wordpress, but it is taking me a long time to find which PHP file to edit. Is there a way to know which PHP file generated a given page?
Thanks!
More information:
I understand the basic outline of Wordpress templates like header.php and single.php. However, I am having a hard time walking through the many theme-specific template files and finding which one serves what purpose. Specifically, I am looking at a generated webpage and attempting to edit it. And I am resorting to inserting tags inside each of the probable template files until I find the right one. Is there a way, perhaps through dev-tool, to see which php file generated the DOM?
It is possible to get a list of all the included files through the get_included_files() function in PHP.
Here is a PHP script to set in the footer.php file of your template :
// echo '<!--'; // you can display this code or show it in an HTML comment
$files = get_included_files();
if ($display_only_theme_files === true) {
$theme_folder = get_template_directory();
foreach ($files as $key => $file) {
if (strstr($file, $theme_folder) === false) {
unset($files[$key]);
}
}
}
print_r($files);
// echo '-->'; // you can display this code or show it in an HTML comment
This script will show you all the included files related to your template. In other words, you will have the possibility to know which file template is used.
Please, be sure to use this code only on your development mode and to delete it when you will be in production.
It is sometimes difficult trying to work out which template file within a theme is being used. First thing worth considering is the Wordpress template hierarchy. This page from the Codex and in particular the diagram should be helpful to you;
http://codex.wordpress.org/Template_Hierarchy
Secondly, it can help if you add the body_class method to your theme's header.php. It is designed to allow greater control of CSS through additional specificity, but by viewing the source through your browser dev tools you can quickly look at the classes added to the body tag and work out which template is being used;
http://codex.wordpress.org/Function_Reference/body_class
How about putting a unique HTML comment in each template file?
I'm building a custom template for WordPress and in a couple places I've used PHP if else statements like the following example within the JS in the footer. It works fine but I'm wondering if this is considered "bad practice" and if so what is a better way to handle it?
<script type="text/javascript">
var $submenu = $('.submenu');
// SUBMENU animation
<?php if ( in_category('Collection') == false ) { ?> // if not a Collection subpage
$('.menu li a').each(function() {
if ( $(this).text() == 'Collection' ) { // If is Collection link show submenu on hover
$(this).mouseenter(function() {
$submenu.slideDown();
});
} else { // else close submenu on hover over other menu links
$(this).mouseenter(function() {
$submenu.slideUp();
});
}
});
$('.nav').mouseleave(function() { // close submenu
$submenu.slideUp();
});
<?php } else { ?> // If a Collection subpage always show subnav
$submenu.show();
<?php } ?>
</script>
Whilst there isn't anything really wrong with mixing PHP and JavaScript, I personally find it quite awkward to read and modify, plus it makes moving that code around tricky. For example if you decided to export that JavaScript to an external file, which has numerous benefits:
<script src="myjs.js.php"></script>
This becomes clunky if your JavaScript needs to know certain values in order to calculate in_category('Collection') as you have to start using GET parameters (unless you are depending on session variables, which can get quite compex and unpredictable, especially through asset requests):
<script src="myjs.js.php?random_vars_required=123"></script>
Another point to be wary of is when having a JavaScript file that changes it's content depending on server-side logic, you have to be careful with what the browser is caching (to avoid these type of problems, it basically means you have to change the request URL for each possible outcome of the js file). i.e.
<script src="myjs.js.php?collection=true"></script>
<script src="myjs.js.php?collection=false"></script>
Another downside is by mixing PHP with JS you are likely to end up duplicating the PHP code in numerous places which goes against the DRY principal. This is why the suggested "export data to a javascript variable" is a much nicer idea. However it's best to avoid variables in the global js namespace if possible. Avoiding the global namespace can prove tricky though if you need to share the logic across multiple JavaScript files and don't wish to export your variables at the top of every file.
another possibility
If the logic you are testing is purely boolean in nature, and it also centres around page classification (or sub-region classification), the following is quite a nice way to handle what you are trying to achieve. It's nice mainly because it keeps your PHP and HTML together, and your JS separate.
The following should be placed in whatever template you use to generate your outer HTML:
<?php
$classes = array();
if ( in_category('Collection') ) {
$classes[] = 'collection';
}
$classes = implode(' ', $classes);
?>
<!--
obviously you'd render the rest of the html markup
I've removed it for simplicity
//-->
<body class="<?php echo $classes; ?>"></body>
Then in your JavaScript / jQuery:
if ( $('body.collection').length ) {
/// if collection sub page
}
else {
/// else do otherwise
}
If you'd rather not add a class to your body element, you could always define your boolean check based on something that already exists on one version of the page and not on the other. Although personally I like to keep things clean and only resort to those kind of checks when I know the HTML markup is not going to change much in the future.
Nearly all browsers that the greater world should be worrying about today support multiple classes on elements. So this means even if you have multiple things you wish to check for, as long as it makes sense, you can place these classes on your html or body tag and use jQuery's Sizzle implementation to find them for you.
Building javascript server-side is probably something we've all done, despite the main arguments for not doing so - namely that the js can't be (easily) validated (with eg. jsLint), and can't (easily) be put into a .js file - there's no point allowing the browser to cache just one of two or more possible versions of the script.
You could consider trading off server-side branching for client-side branching, which arguably makes the code more readable but, more importantly, is an intermediate step to my final suggestion (bear with me) :
var $submenu = $('.submenu');
// SUBMENU animation
var isCollection = <?php echo in_category('Collection') ? 'false' : 'true' ?>;
if ( !isCollection ) { // if not a Collection subpage
$('.menu li a').each(function() {
if ( $(this).text() == 'Collection' ) { // If is Collection link show submenu on hover
$(this).mouseenter(function() {
$submenu.slideDown();
});
} else { // else close submenu on hover over other menu links
$(this).mouseenter(function() {
$submenu.slideUp();
});
}
});
$('.nav').mouseleave(function() { // close submenu
$submenu.slideUp();
});
} else { // If a Collection subpage always show subnav
$submenu.show();
}
However, if the boolean isCollection could be determined by another means (eg. by enquiring some aspect of the DOM such as a data-xxx attribute), then you're cooking with gas. Only one version of the js script would be necessary; it could be easily validated with jsLint; and could be moved into a .js file if desired.
Of course you need to set the data-xxx attribute (or whatever) elsewhere in the server-side code (complete with an explanatory comment), which is a possible downside, but maybe not a big one.
Maybe not all js would be amenable to this approach but I think the example in the question would be.
To my mind, this is a viable way ahead on this occasion.
At least its not a sign of great code. There are alternatives:
Generate a JSON object and parse it in JavaScript
Dynamic inclusion of JS files
Just set conditions:
if(<?= (int)$mybool ?>) {
doSomething();
}
We have a couple of pages that require special care, jquery-ui will be called from external scripts which are going to "somehow" be added to the head section of an article.
I've attempted with jumi, however it isn't the best choice(including a js in stead of php would render it in html body), the only way I could add a javascript file was by including a php file which would echo a , but as one would imagine, this isn't elegant nor efficient in terms of performance.
Another attempt was, in stead of echoing a script, I've tried using:
<?php
$document = &JFactory::getDocument();
$document->addScript( "path/to/jsfile.js" );
?>
but it didn't work as I've expected, it seems that joomla creates the head section before this php script has the chance of being executed.
I've also gave easy header a go, however, it seems that it will include the files in all articles, which I do not wish since it will have a pretty big impact in terms of bandwidth and possible javascript issues down the road.
I'm farily new to joomla so anything that would provide some flexibility is good as an answer.
If something isn't unclear, please ask, I will try to answer the best I can.
Please note that I'm using joomla 1.7 and php5.
Jumi uses the onAfterRender event (looking at the 2.0.6 plugin) - by this time I think the <head> tag has already been written out, in-fact the whole document is already rendered.
You could try getting the document body and then searching for the closing tag </head> and inserting the script link before it. Something like this:
$myJS = "<script type='text/javascript' src='http://mysever.com/my.js'>"
$content = JResponse::getBody(); // gets the html in it's ready to send to browser form
$hdPos = strpos($content, '</head>');
$hdPos += 7; //move position to include the <head> tag
$bodyLen = strlen($content);
$content = substr($content, 0, $hdPos) . $myJS . substr($content, $hdPos, $bodyLen);
JResponse::setBody($content);
NB: This is untested and I don't use Jumi these days but it should be close.
You didn't have to go through all this!
Go to: extensions -> template manager -> templates tab (its on "styles" by default) -> go to your template and click on "edit HTML". You'll be able to add your code directly in the header, and it will be loaded in all the pages.
A bit more elegant way is to define a function that does what you want in the header - and call it from the body of the specific article you want.
Situation:
A PHP Templating system that is responsible for building a pages HTML.
Javascript core functions are all in external files
Each Template has some default Javascript Functions that need to be called on a per/template basis
When A page is rendered, I next need to call a set of Javascript functions: i.e.
<script type="text/javascript">
$(document).ready(function{
API.loadThis(); // all these Javascript functions are in an external JS file
API.loadThat();
API.buildDateSelector("#idForSelector");
// etc
});
</script>
Up until now I have just appended that as text to each of the HTML templates. However, in the case of a Page that consists of multiple smaller Templates (each possibly containing their own initialization Javascript), then I have multiple bits of inline Javascript thrown all over my webpage.
My question is:
how should I properly organize everything so that I can easily "register" or "trigger" some default Javascript to be called upon page load?
Or is appending each block of Javascript to each template (like above) appropriate?
What I would do is quite similar to #Chris. However, I'd suggest a few minor changes:
Add a parameter to the addJS function which indicates the position on the page. By default you should have support for at least head and foot (head would place it in the head, foot would place it right before the closing </body>).
public function addJS($string, $position = 'head') {
if (!is_array($this->js[$position])) {
$this->js[$position] = array($string);
} elseif (!in_array($string, $this->js[$position])) {
$this->js[$position][] = $string;
}
}
Then, include tokens in the template to indicate the positions:
{{js_head}}
</head>
<body>
<!--content here-->
{{js_foot}}
</body>
Then, when rendering, just do something like:
$js = $this->js;
$positions = preg_replace_callback(
'/{{js_(inline_)?([a-zA-Z0-9]+)}}/',
function ($match) use ($js) {
if (isset($js[$match[2]])) {
$js = implode("\n", $js[$match[2]]);
if ($match[1] == 'inline') {
return $js;
} else {
return '<script type="text/javascript">'.$js.'</script>';
}
return '';
},
$templateBody
);
Now, the real benefit is that your templates can cleanly and trivially define their own positions for re-used and commonly used bits:
$this->addJS('return this.form.submit();', 'submit_form');
$html = '
<input type="text" onblur="{{js_inline_submit_form}}" />
<button name="submit" onclick="{{js_inline_submit_form}}" />
';
It can be quite useful since now you're not duplicating the JS calls everywhere in your code. Plus, it'll reduce the overhead of wrapping each output in <script> tags (since it wraps the entire position in the tags, rather than each piece of content)...
This would allow you to then take all of the non-inline JS and compile a series of files at run-time to send to the browser to take care of caching. It adds the benefit of being able to keep your JS close to your views (for maintainability) yet still serve cached JS and not have to re-send it every time...
public function buildJSCache($position) {
if (!isset($this->js[$position]) || empty($this->js[$position])) {
return '';
}
$file = implode($this->js[$position]);
$name = 'js/'.md5($file) .'.js';
if (!file_exists($name)) {
file_put_contents($name, $file);
}
return $name;
}
Then, in your template code, just do:
$replace = $this->buildJSCache('head');
if ($replace) {
$replace = '<script type="text/javascript" src="'.$filename.'"></script>';
}
$template = str_replace('{{js_head}}', $replace, $template);
You get the double-win of maintainability and speed to the user (you could even minify it if you wanted).
Note: all of this code is demonstration only, if you were to use it in production, I'd clean it up and think it out a bit further...
That's my $0.02 at least...
There are a lot of ways to do this. I suggest that you get some open source frameworks, look at how they do things and decide on your preferences. Some techniques are considered "best practice", but a lot of a framework's structure boils down to developer preference.
I have a framework I use for my own projects that is similar to what you describe, each of the smaller templates is termed as a "component". Each component is able to add any amount of javascript to itself using an addJS() method, likewise for css and html. A top-level controller loops through a given page's content (in terms of components). This give me a chance to have all the css, javascript, and html loaded ahead of time. Then, I can output them in whatever order I see fit.
So:
page controller handles request
inits one or more components
component load method populates html, javascript, and css class properties (arrays of file names, string for html)
for itself
components has its own set of templates, js, css
outputs site-wide templates
includes all component css within page header
iterates through components, outputs component html, layout stuff
outputs component JS for page footer
I have a components folder, within it are folders for each component. Within each component folder is a php file (that component's handler), optionally one or more css/js files. This keeps everything organized nicely.
I need to use drupal_add_css to call stylesheets onto single Drupal 6 pages. I don't want to edit the main theme stylesheet as there will be a set of individual pages which all need completely new styles - the main sheet would be massive if i put it all in there.
My solution was to edit the page in PHP editor mode and do this:
<?php
drupal_add_css("/styles/file1.css", "theme");
?>
<div id="newPageContent">stuff here in html</div>
But when I view source, there is nothing there! Not even a broken CSS link or anything, it's just refusing to add the CSS sheet to the CSS package put into the page head.
Variations don't seem to work either:
drupal_add_css($path = '/styles/file1.css', $type = 'module', $media = 'all', $preprocess = TRUE)
My template header looks like this, I've not changed anything from the default other than adding a custom JavaScript.
<head>
<?php print $head ?>
<title><?php print $head_title ?></title>
<?php print $styles ?>
<?php print $scripts ?>
<script type="text/javascript" src="<?php print base_path() ?>misc/askme.js"></script>
<!--[if lt IE 7]>
<?php print phptemplate_get_ie_styles(); ?>
<![endif]-->
</head>
Why is this function not working?
It is not quite clear where you are selecting the template that you have in your example. If you are selecting it from a module then you can just use drupal_add_css in the module rather than the template.
If you have your own theme you can use template_preprocess_page and put logic in there to add the relevant CSS (you can also use it to select the template to use).
I have noticed something weird and it might fix your problem:
drupal_add_css( drupal_get_path('theme','themname') . '/working.css','module' ,'all' , false );
drupal_add_css( drupal_get_path('theme','themname') . '/path/to/folder/notworking.css','module' ,'all' , false );
The first one will work ebcause the style it in the main them folder
The second line will not work because the style is in a sub folder !
Edit:
i think it did not work because i did not write the path the the style file properly :S so please disregard my answer
drupal_add_css( drupal_get_path('theme','test') . '/pages/subpage/style.css','theme');
is working
This function wont work in templates. The reason is that the variable $styles which will hold all the stylesheet html will already have been generated at this point, so drupal_add_css wont work as it adds to that. if you want to do this in your theme, you would probably have to add the css file manually
<link rel="stylesheet" ... />
The other way would be to use drupal_add_css in a module, but you might have a hard time adding the correct css files on the pages you want.
It's possible to use drupal_add_css() inside your template.php file; this page has a good example of how to do just that.
Thanks for the link, wyrmmage. That's very useful. I think the rest of the code in the page is unneccessary. You probably just need these since drupal 6 already automatically check for file existence:
drupal_add_css(path_to_theme() . '/css/yourcss.css', 'theme');
// Add the following to regenerate $styles.
// This is needed for template_preprocess_page() since css is already generated at this point.
$variables['styles'] = drupal_get_css();
Answer was very much to use the CSS Injector module - great little addon!
Here is an excerpt from its project page:
Allows administrators to inject CSS into the page output based on configurable rules. It's useful for adding simple CSS tweaks without modifying a site's official theme. The CSS is added using Drupal's standard drupal_add_css() function and respects page caching, etc. The 2.x brach leverages CTools so CSS can be included with Feature changes (ie. CSS that improves the look of a View can be packaged with the View).
This code inside template.php works for me:
function alagna_preprocess_page(&$vars) {
drupal_add_css(path_to_theme() . '/header_1.css', 'theme');
$vars['css'] = drupal_add_css();
$vars['styles'] = drupal_get_css();
}
explained:
alagna is the theme name
header_1.css is the css file required.
drupal_add_css is expecting a path relative to base path whereas drupal_get_path does not return the path relative to base path.
global $base_path;
drupal_add_css($base_path . drupal_get_path('module / theme','name') . "/styles/file1.css", "module / theme");
You can choose between module and theme accordingly.
Try this
common.inc drupal_get_css($css = NULL)
Parameters
$css: (optional) An array of CSS files. If no array is provided, the default stylesheets array is used instead.
$css = $vars['css'];
// unset the system css files
$unset_css = array
'modules/system/system.css',
'modules/system/system-menus.css',
);
foreach($unset_css as $css_f) {
if(isset($css['all']['module'][$css_f])) {
unset($css['all']['module'][$css_f]);
}
}
// add css
$css['all']['theme'][drupal_get_path('theme', 'openpublish_theme') . '/css/style.css'] = true;
$vars['styles'] = drupal_get_css($css);