How do I alter a node template from a module in Drupal 8? - drupal

I would like my custom Drupal 8 module to force a different template for pages that match a certain URL. Here is my module structure:
/sass_edit
/css
/js
/template
builder_template.html.twig // this is the template file
sass_edit.module
...
sass_edit.*.yml // various yml files
These are the contents of builder_template.html.twig:
<h1>test</h1>
Here are the relevant lines of code in my .module file:
function sass_edit_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
$current_path = \Drupal::service('path.current')->getPath();
if(\Drupal::currentUser()->isAuthenticated() && strpos($current_path, "/builder/") >= 0) {
$suggestions[] = 'builder_template';
}
// kint($suggestions);
// die();
}
When I visit a page whose URL contains /builder/, the code runs and adds the string builder_template to the $suggestions array. However, when the page is rendered, the new template is ignored. I have tried flushing caches, with no results.
I'm not sure how to proceed. All the documentation I've found refers to adding theme suggestions from a custom theme, not a custom module.
Any idea what I'm doing wrong? Thank you so much for any help!

Maybe you have a typo in the code you pasted but the folder where you have your templates overrides should be templates and not template as you wrote. Don't forget to flush caches after changing the name of the directory ;)

Related

Drupal, how to Remove Login or comment link from webform pages?

I want to remove the Login or register to post comments text from the page where I created a webform; is there any suggestion as to how can i use hook_link_alter() with this?
This code resides in comment.module file under the theme_comment_post_forbidden() function.
If you are using Drupal 7, you may use hook_node_view_alter or hook_entity_view_alter to modify the displayed content.
function foo_node_view_alter (&$build) {
if ($build['#node']->type == 'webform') {
// remove login or register to post comments
unset($build['links']['comment']['#links']['comment_forbidden']);
// remove add comments
unset($build['links']['comment']['#links']['comment_add']);
}
}
In case you want to use hook_link_alter in Drupal 6, use this code in your custom module
function comment_link_alter (&$links, $node) {
if ($node->type == 'webform') {
// remove register or login to post comments
unset($links['comment_forbidden']);
// remove add a comment
unset($links['comment_add']);
}
}
If you are working with a content type, you could over-ride the theme.
copy the template file '/modules/node/node.tpl.php' into your theme's 'templates' directory
rename the file, calling it 'node--NODETYPE-tpl.php' (that's two hyphens after 'node'). For example, 'node--book-tpl.php' for a 'book' content type.
comment out the final two lines (or delete them):
// print render($content['links']);
// print render($content['comments']);

How can I customize a specific node in Drupal 6 WHEN a custom template has already been applied to the node's content type?

[For Drupal 6] Let's say I've created a content type called "my_content_type". I can override the default template for that entire content-type by creating "page-node-my_content_type.tpl.php". But, what would be the best way to then further customize a single node of that content type (e.g., node 5555)?
I tried the following, but none worked:
page-node-5555.tpl.php
page-node-my_content_theme-5555.tpl.php
node-5555.tpl.php
None of these work. They all continue to use my original content-type template.
Drupal's page templates work on a suggestion system. Based on the current URL, an array of possible template files is created. It loops through the array (in reverse order) looking for template files that exists. The first one it finds, it will use.
drupal's theme system provides a hook for you to modify the template suggestions.. open up your template.php and find
function phptemplate_preprocess_page(&$vars) {
the $vars variable is what contains the suggestions, specifically $vars['template_files']
By default the only page suggestions that are available are
page.tpl.php
page-node.tpl.php
page-node-[node_id].tpl.php
As far as im aware, page-node-[node_type].tpl.php does not work by default, so its likely you have already modified the preprocess_page template to added in this functionality.
However if you want to add more specific templates you could do something like this...
function phptemplate_preprocess_page(&$variables) {
if ($variables['node']->type != "") {
$variables['template_files'][] = "page-node-" . $variables['node']->type;
$variables['template_files'][] = "page-node-" . $variables['node']->type . "-" . $variables['node']->nid;
}
}
this will allow the following hierarchy of template suggestions
page.tpl.php
page-node.tpl.php
page-node-[node_id].tpl.php
page-node-[node_type].tpl.php
page-node-[node_type]-[node_id].tpl.php
In Drupal 7 just copy the page.tpl.php template and rename it as
page--node--[node:id].tpl.php
Clear cache and start tweaking..
function phptemplate_preprocess_page(&$variables) {
if ($variables['node']->type != "") {
$variables['template_files'][] = "page-node-" . $variables['node']->type;
$variables['template_files'][] = "page-node-" . $variables['node']->type . "-" . $variables['node']->nid;
}
}
This code should not work because hook_preprocess_page() does not get passed any node information. hook_preprocess_node() does. So you can easily create a custom node.tpl, but you cannot easily create a custom page.tpl for a specific node. Not that I've been able to figure out anyway :)
Later...
In default Drupal, page-node-NID.tpl.php will work with no special coding. On a site of mine, it wasn't working, however, and I used the following code to make it work:
/**
* Implementation of hook_preprocess_page().
*/
function MYMODULE_preprocess_page(&$variables) {
// Allow per-node theming of page.tpl
if (arg(0) == 'node' && is_numeric(arg(1))) {
$variables['template_files'][] = "page-node-" . arg(1);
}
}

Drupal 6 & 7 unset Javascript from header

EDIT: My question applies to Drupal 6 & 7, though my code example is Drupal 6. People have provided answers are useful for both versions of Drupal.
I'm currently working in Drupal creating a mobile theme for a Drupal 6 website and trying to remove all unnecessary core and module JavaScript and css through the preprocess_page function in my template.php file. The css files are successfully removed, but I can't seem to get the JavaScript to be removed. Here's what I've got. In this example, everything is successfully removed except for the the ajax scripts.
Any idea what I'm doing wrong?
<?php
function mytheme_preprocess_page(&$vars) {
//////// remove unneccesary drupal head files for mobile version
// CSS
$css = drupal_add_css();
// core
unset($css['all']['module']['modules/user/user.css']);
unset($css['all']['module']['modules/node/node.css']);
unset($css['all']['module']['modules/system/defaults.css']);
unset($css['all']['module']['modules/system/system.css']);
unset($css['all']['module']['modules/system/system-menus.css']);
// contributed -- automatically generate the path—— just easier this way
$rm[] = drupal_get_path('module','filefield').'/filefield.css';
$rm[] = drupal_get_path('module','flickr').'/flickr.css';
$rm[] = drupal_get_path('module','logintoboggan').'/logintoboggan.css';
$rm[] = drupal_get_path('module','logintoboggan').'/logintoboggan.css';
$rm[] = drupal_get_path('module','fieldgroup').'/fieldgroup.css';
$rm[] = drupal_get_path('module','views').'/css/views.css';
$rm[] = drupal_get_path('module','content').'/theme/content-module.css';
// remove the contribs from the array
foreach ($rm as $key => $value) {
unset($css['all']['module'][$value]);
}
// JAVASCRIPT
$scripts = drupal_add_js();
unset($scripts['module']['sites/all/modules/ajax/ajax.js']);
unset($scripts['module']['sites/all/modules/ajax/jquery/jquery.a_form.packed.js']);
// recreate the tempalate variables
$vars['styles'] = drupal_get_css($css);
$vars['scripts'] = drupal_get_js('header', $scripts);
}
?>
ETA: Here is the way the scripts print out in the header:
<script type="text/javascript" src="/sites/all/modules/ajax/jquery/jquery.a_form.packed.js?P"></script>
<script type="text/javascript" src="/sites/all/modules/ajax/ajax.js?P"></script>
I found a potentially better solution for this sort of problem. I tried Kerri's approach since Matt V says it worked for him, but I really didn't want to edit template.php if I could avoid it and regardless it wasn't working in my environment. My problem was that a couple JS files throw errors on one particular page. All I did was write a very simple new module that only runs on the desired page. So- I created a basic .info file and below is the .module code. Worked like a charm for me. Just replace "mysite_mymodule" with whatever you name your module and replace "my-page-alias" with whatever page alias you're trying to effect.
<?php
/**
* Implements hook_js_alter().
*/
function mysite_mymodule_js_alter(&$javascript) {
$alias = drupal_get_path_alias($_GET['q']);
if ($alias == "my-page-alias") {
/**
* documentation about what I did and why I did it...
*/
unset($javascript['sites/all/modules/dhtml_menu/dhtml_menu.js']);
unset($javascript['sites/all/modules/apachesolr_autocomplete/apachesolr_autocomplete.js']);
}
}
You can directly use the drupal header in drupal 7.
you can clean the other module javascript you don't need
function module_preprocess_page(&$vars) {
// clean unnecesary script from the page
if (arg(0) != 'admin' || !(arg(1) == 'add' && arg(2) == 'edit') || arg(0) != 'panels' || arg(0) != 'ctools') {
$javascript = &drupal_static('drupal_add_js', array());
unset($javascript['misc/jquery.js']);
unset($javascript['misc/jquery.once.js']);
drupal_static('drupal_add_js', $javascript);
}
}
The Ajax module uses hook_preprocess_page to add its scripts. The Ajax module may be executing its hook implementation after your module. If that's the case, you could adjust the weight of your module, to fire after Ajax. You could check first to make sure, by outputting the contents of $scripts (using something like the Devel module's dpm() function), just before you do the unsetting.
UPDATE: Since you're making the changes in a template preprocess function, my initial hypothesis about it being an issue of module weights wouldn't apply. I added your template function on a test site and it removed those two scripts, for me. I had to adjust the path because my ajax module was under /sites/all/modules/contrib. That's just where I happen to keep my contrib modules, but you might double check that you're using the right path.
Another thing that threw me off for a few minutes was that I accidentally added the code to the wrong theme; so, that's another thing to check. Also, check that Javascript caching is disabled on the Performance page.
You have to do it the other way around. Unsetting files of other contrib modules explicitly couples your module to every other module that outputs js to the header. You won't be able to maintain that for too long before it breaks. What happens when more js files get added by contrib modules?
You're best to create a mask of paths you want to output and unset everything except those.
Drupal 7 has some hooks that will let you do that but I can't remember them. If you're on D6 you're kinda stuck.
I did write a dirty workaround for Drupal 6 for this same problem with css files. Here is the whole module (it was only 3 functions). I'm sure you can adapt it to js files too.
Create your mask (expose it to the variables table)
function destroy_mask_styles() {
return variable_get('destroy_mask_styles', array('all/modules/mymodule', 'themes/mytheme'));
}
Then here comes the dodgey part. This function looks for the paths of the css files in the header and unsets them if they don't match.
function destroy_styles($var_styles) {
//this is a bit dodgey. But it's probably the easiest way to implement
$masks = destroy_mask_styles();
$styles = array();
foreach(explode("\n", $var_styles) as $style) {
foreach($masks as $mask) {
if(strpos($style, $mask) > 0) {
$styles[] = $style;
}
}
}
return implode("\n", $styles);
}
Then in preprocess_page, (this might be considered where the dodgyness happens)
function destroy_preprocess_page(&$variables) {
//destroy some css and scripts we don't want
$styles = destroy_styles($variables['styles']);
$variables['styles'] = empty($styles) ? $variables['styles'] : $styles;
}
If you want to include everything from one module (for example), just alter the paths that get matched to include the path to the module's root folder. Don't worry about file names.
Remember that this is not the ideal way to do this. There might be a better way in D6 but there are no hooks here so probably not.
Good luck!

custom page.tpl.php for a drupal view

How can I create a custom page.tpl.php for a specific view?
I'm not talking about styling the view itself, just the page where that view gets rendered.
Thank you.
#Keith Morgan - It's page.
Per Allartk's solution
In Drupal 7 template.php:
function <theme>_preprocess_page(&$variables) {
if (($views_page = views_get_page_view()) && $views_page->name === "galleries") {
$variables['theme_hook_suggestions'][] = 'page__views__galleries';
}
}
Then in your theme directory, create the page--views--galleries.tpl.php file.
Clear drupal cache and template should work.
I used 'galleries' as and example views name.
You can create a template file to theme almost any aspect of views output. In your case you want to create a custom template for your page display.
On the view designer, click the Theme link in Basic Settings. You'll see some template file naming options depending on if you want to theme the whole view (e.g., views-view--example--page.tpl.php), each row (e.g., views-view-fields--example--page.tpl.php) and so on.
Copy the appropriate template you want to customize from /sites/all/modules/views/theme to your theme and customize as you wish.
Once you create your custom template file, you can go back to the view designer Theme link to make sure it is being used. Your template should be bolded.
Hope this helps.
There's some documentation on template suggestions, and you might be interested in page.tpl.php suggestions. If it's a page view, you could use a path suggestion. So if your view is at http://www.example.com/photos, the page.tpl.php file would be named page-photos.tpl.php.
Had a similar problem, which was remedied by putting a .tpl.php in my theme's template folder. The naming convention for a page display of views in drupal 7 is page--path-to-view.tpl.php
In a drupal 7 theme I added a template suggestion in template.php:
function sovon_preprocess_page(&$variables) {
if(views_get_page_view()) {
$variables['theme_hook_suggestions'][] = 'page__view';
}
}
See http://api.drupalize.me/api/drupal/function/views_get_page_view/7 and http://drupal.org/node/223440#custom-suggestions for more information.
Assuming a view as a page, you can use the results of page_manager_get_current_page() in your preprocess to determine if your view is active, then take the appropriate steps (tack on body classes, add a template suggestion, etc).
using sillygwailo's suggestion I got this to work for me very nicely:
function YOUR-THEME-NAME_preprocess_page(&$vars) {
//allow template suggestions based on url paths.
$alias = drupal_get_path_alias(str_replace('/edit','',$_GET['q']));
if ($alias != $_GET['q']) { $suggestions = array();
$template_filename = 'page';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$suggestions[] = $template_filename;
}
$alias_array = explode('/', $alias);
$variables['template_files'] = $suggestions;
Then if your view is at www.example.com/photos , create a page-photos.tpl.php in your theme directory and drupal will use that as your template.
If that checked answer doesnt work(because it didnt for me) you can create a page--(urlname).tpl.php and then style your theme however you want it. Then you can import your view in one of several ways ...
print render($page['content']);
or
$view = views_get_view('viewname');
print $view->execute_display('default', $args);
$args is just an array and can be blank..you can just leave it off entirely

Include CSS or Javascript file for specific node in Drupal 6

What is the best method for including a CSS or Javascript file for a specific node in Drupal 6.
I want to create a page on my site that has a little javascript application running, so the CSS and javascript is specific to that page and would not want to be included in other page loads at all.
I'd advise against using hook_nodeapi for that. Adding CSS and Javascript is related to layout so hook_nodeapi is not the place for it: use themeing. This way, you can override those files when you're going to develop a new theme. Doing that with the nodeapi approach would be a bit harder (you'd have to search the js/css list for the files, remove them and replace them with your own).
Anyway: what you need to do is add a node preprocess function that adds those files for you. You can do this either in a module or in a custom theme. For a module this would be:
function mymodule_preprocess_node(&$variables) {
$node = $variables['node'];
if (!empty($node) && $node->nid == $the_specific_node_id) {
drupal_add_js(drupal_get_path('module', 'mymodule') . "/file.js", "module");
drupal_add_css(drupal_get_path('module', 'mymodule') . "/file.css", "module");
}
}
or for a theme:
function mytheme_preprocess_node(&$variables) {
$node = $variables['node'];
if (!empty($node) && $node->nid == $the_specific_node_id) {
drupal_add_js(path_to_theme() . "/file.js", "theme");
drupal_add_css(path_to_theme(). "/file.css", "theme");
}
}
Don't forget to clear the cache, first.
These functions are called before the node is themed. Specifing the js/css there allows for a cascaded approach: you can have the generic/basic stuff in the module and provide enhanced or specific functionality in the theme.
I use the preprocess functions but this has some issues. $variables['styles'] is usually set before the node preprocess function is called. In other words drupal_get_css is already called which makes you calling drupal_add_css useless. The same goes for drupal_add_js. I work around this by resetting the $variables['styles'] value.
function mytheme_preprocess_node(&$variables) {
$node = $variables['node'];
if (!empty($node) && $node->nid == $the_specific_node_id) {
drupal_add_js(path_to_theme() . "/file.js", "theme");
drupal_add_css(path_to_theme(). "/file.css", "theme");
$variables['styles'] = drupal_get_css();
$variables['script'] = drupal_get_js();
}
}
This seems to work for most cases.
P.S. There's hardly any ever need to create a module to solve a theming problem.
Cheers.
This seems like a good solution:
http://drupal.org/project/js_injector
and
http://drupal.org/project/css_injector
It works when you want to insert inline code into something other than technically a node so there's no node id and no PHP input option available. Like I used it to inject small jQuery tweaks into a couple of admin pages. It works by path rather than node id.
The best solution I've come up with so far is to enable the PHP input mode, and then call drupal_add_css and drupal_add_js as appropriate in a PHP block in the start of the body of your node.
This should do the trick - a quickie module that uses the hook_nodeapi to insert the JS/CSS when the node is viewed.
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
// the node ID of the node you want to modify
$node_to_modify = 6;
// do it!
if($op == 'view' && $node->nid == $node_to_modify) {
drupal_add_js(drupal_get_path('module', 'mymodule') . '/mymodule.js');
drupal_add_css(drupal_get_path('module', 'mymodule') . '/mymodule.css');
}
}
This avoids security issues with enabling the PHP input filter, and doesn't require a separate node template file which could become outdated if you updated the main node template and forgot about your custom one.
You can have a custom template for that node (node-needsjs.tpl.php) which calls the javascript. That's a little cleaner than using PHP right in the node body, and makes changes to content easier in the future.
EDIT: I don't think I was very clear above. You want to name the template file node-(nodeid).tpl.php. So if it was Node 1, call the file node-1.tpl.php

Resources