switching templates dynamically in wordpress - wordpress

Right now I'm trying to switch the template that Wordpress uses depending on the device that is viewing the site.
The exact issue here is that the ONLY thing that seems to be switching are the scripts and stylesheets. The actual templates them selves (index, header, footer) stay the same.
Here is the function I'm using to do this:
<?
function fxn_change_theme($device) {
$header = $_SERVER['HTTP_X_UA_DEVICE'];
if ($header === 'mobile') {
$theme = 'jankness-mobile';
} elseif ($header === 'tablet') {
$theme = 'jankness-tablet';
} else {
$theme = 'jankness-desktop';
}
return $theme;
}
add_filter('template', 'fxn_change_theme');
add_filter('option_template', 'fxn_change_theme');
add_filter('option_stylesheet', 'fxn_change_theme');
?>
Also, the only filter that's doing anything seems to be 'template', the option filters don't do much. I've tried looking up what they do and it's not clear to me at the moment.
What might be the issue here?

Basically, since the code I was using was sitting in functions.php it was not able to manipulate the theme content earlier enough in the Wordpress core process. So the solution was to move the code into a very simple plugin exactly as it is, and hook in to the theme_setup point using the same code I used here.

Related

How can I add no-follow to all links in a WordPress site in one go?

I'm coding a WordPress website in which I want all the external links to be "no-follow" by default.
It is quite long to go and edit each single link to add the "no-follow", is there a way to code it once for all?
Thank you
IMHO, the best way to do so is using a custom filter. Being generated dinamically by PHP, you can edit links on post and pages server-side even before a user visit them: WordPress used to add rel="nofollow" to each link by default in the past, but I see it doesn’t happen anymore. Then, I found a solution by Debjit Saha you may try on functions.php.
add_filter('the_content', 'my_nofollow');
add_filter('the_excerpt', 'my_nofollow');
function my_nofollow($content) {
return preg_replace_callback('/<a[^>]+/', 'my_nofollow_callback', $content);
}
function my_nofollow_callback($matches) {
$link = $matches[0];
$site_link = get_bloginfo('url');
if (strpos($link, 'rel') === false) {
$link = preg_replace("%(href=\S(?!$site_link))%i", 'rel="nofollow" $1', $link);
} elseif (preg_match("%href=\S(?!$site_link)%i", $link)) {
$link = preg_replace('/rel=\S(?!nofollow)\S*/i', 'rel="nofollow"', $link);
}
return $link;
}
Please, notice that some plugins could break this code and I’ve never tried this on newer WordPress versions.
One way you can do it is using JavaScript:
var hrefToCheck = "mysite.com" // change this string
noFollowExternalLinks(hrefToCheck); // call to run the function below
function noFollowExternalLinks(siteHref) {
document.querySelectorAll('a').forEach(function(link) {
if (!link.href.includes(siteHref)) {
link.setAttribute("rel", "nofollow");
}
})
}
So, you can change hrefToCheck variable to a piece of your site URL that will be checked inside each link inside the page.
The function will loop to check every link in the page and apply rel="nofollow" to all external links (that don't match the text in the variable).

WordPress / CF7 - Customising the Contact Form 7 ajax loader gif, depending on location

I am using the Contact Form 7 plugin on a web site, which has a contact form in the footer of every page and also a contact form in the main area of a dedicated Contact page.
I know how to customise the ajax loader gif in CF7...
function my_wpcf7_ajax_loader () {
return get_stylesheet_directory_uri() . '/images/my-loader-image.gif';
}
add_filter('wpcf7_ajax_loader', 'my_wpcf7_ajax_loader');
...but my problem is that I need to specify two different loader images - one for the footer form and one for the Contact page form. (The reason for this is because one form is on a white background and the other is on a red background, and despite experimenting with different loader gifs I don't think it is possible to have a loader gif that looks good on both.)
Here's the solution: https://gist.github.com/tctc91/8271205
add_filter('wpcf7_ajax_loader', 'my_wpcf7_ajax_loader');
function my_wpcf7_ajax_loader () {
return network_home_url() . '/assets/themes/ips-helpdesk/images/ajax-loader.gif';
}
As loading image is an img element with src attribute, css methods will not be helpful.
It would be required to change src attribute of img tag through JavaScript and without modifying the core js of contact 7 form plugin (to allow plugin upgrades in future), I have come with following JavaScript solution to apply this change by bruteforce method.
(function($) {
setInterval(function() {
if(typeof $.fn.wpcf7InitForm != "undefined") {
//Contact Form 7 is loaded and initialized
$loaderImage = $("#wpcf7-f52-o2 img.ajax-loader"); // modify your selector accordingly
if(!$loaderImage.data("pathChanged")) {
$loaderImage.attr("src", "ALTERNATIVE_IMAGE_PATH");
$loaderImage.data("pathChanged", true);
}
}
}, 2000);
})(jQuery);
Though it may not be the best way, See if it helps.
I read an article with a solid solution for your problem. They gave this solution:
// Change the URL to the ajax-loader image
function change_wpcf7_ajax_loader($content) {
if ( is_page('contact') ) {
$string = $content;
$pattern = '/(<img class="ajax-loader" style="visibility: hidden;" alt="ajax loader" src=")(.*)(" \/>)/i';
$replacement = "$1".get_template_directory_uri()."/images/ajax-loader.gif$3";
$content = preg_replace($pattern, $replacement, $string);
}
return $content;
}
add_filter( 'the_content', 'change_wpcf7_ajax_loader', 100 );
link to the article here:
Note: We're using a heavily modified twenty twenty theme and NONE of these solutions worked. Tried them all. Updated to latest version of plugin, still the same issue. Can't disabled plugins one at a time and test by practical means because there are dozens and because we need the ones that we have.

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!

How to hide Edit | View tabs?

Can I hide the
Edit | View
tabs on top of each node ?
I've searched for this option in theme settings (both global and standard theme but I couldn't find it).
I still want to be able my customer to edit / administer content, so I cannot just remove the permission for it.
thanks
here is a very easy solution for you. (Drupal 7)
Open your page.tpl.php in your current template and search for the $tabs variable.
Remove the render code if you want to hide it completely.
If you want to display it only to administrators use this code
<?php if ($tabs and $is_admin): ?>
<div class="tabs">
<?php print render($tabs); ?>
</div>
The above code checks if the user is administrator. If it is it will render the tabs. If not it wont render them.
This really is a presentational thing, not a functionality thing, so it should be done at the theme level.
The problem with overriding theme_menu_local_tasks() is that you override/take a hatchet to the entire local task display, when you really just want to get in there with a scalpel to remove two specific local tasks. So, you need to get a little more specific.
theme_menu_local_tasks() gets the current page's local tasks and passes them to menu_local_tasks(). Here, two theme functions are used:
theme_menu_item_link(), which gets the link markup for the task
theme_menu_local_task(), which gets the <li> element for the task.
So, you can get rid of the View and Edit local tasks in a really robust way by overriding theme_menu_item_link() and theme_menu_local_task() to include your check for them:
function mytheme_menu_item_link($link) {
// Local tasks for view and edit nodes shouldn't be displayed.
if ($link['type'] & MENU_LOCAL_TASK && ($link['path'] === 'node/%/edit' || $link['path'] === 'node/%/view')) {
return '';
}
else {
if (empty($link['localized_options'])) {
$link['localized_options'] = array();
}
return l($link['title'], $link['href'], $link['localized_options']);
}
}
function mytheme_menu_local_task($link, $active = FALSE) {
// Don't return a <li> element if $link is empty
if ($link === '') {
return '';
}
else {
return '<li '. ($active ? 'class="active" ' : '') .'>'. $link ."</li>\n";
}
}
This way, you're relying on the menu router path, not modifying the menu router item, and achieving the result you want with minimal changes to core functionality or theming.
On the module side, you could do something that decouples the Edit's menu entry from the local tasks for the node:
function custom_menu_alter(&$items) {
$items['node/%node/edit']['type'] = MENU_CALLBACK;
}
The edit path is still there, but now it is not associated with the View tab. This includes the edit page itself--no View tab there.
there is a module for that: tab tamer allows to hide or disable tabs and rename them as well.
I use the following in template.php by theme (which is perhaps a little hacky, I feel I should be considering unsetting $tabs instead):
function THEME_NAME_menu_local_tasks() {
return '';
}
Or you could ommit:
if ($tabs) echo $tabs;
from your page.tpl.php...
View and Edit are functional features. They have a reason for being there.
The best way to "remove" them, is to "remove" that functionality alltogether. After all: why remove the interface of a piece of functionality, but not the functionality itself?
Besides, simply not printing the tabs, does not remove the url endpoints. In other words: if you don't print the edit tab, people can still access the edit page.
Again: best is to remove that functionality: The fact that you don't want the edit tab, sounds as if you don't want the edit functionality for certain users.
If so, then just remove that permission for that role. That is all. The tabs will be gone.
If, however, you simply wish to display these tabs differently, Drupal is your friends. As you may have noticed, they are called local tasks and not tabs. That is because the theme decides how to render them: The theme is the thing that decides to show them as tabs.
Simply override the theme_menu_local_tasks() to create your own HTML for the "local-tasks". And in your page-tpl, simply move the $tabs variable around to a place, where you want them.
But again: Don't try to change the behavior of the app, by removing interface-elements. That is not the right thing to do: you should change the behavior, in order to change the behavior :)
For all the people stumbling upon this question while looking for a D7 solution: As stated on https://drupal.stackexchange.com/a/77964/15055 it's hook_menu_local_tasks_alter()
/**
* Implements hook_menu_local_tasks_alter() to unset unwanted tabs
*/
function MYMODULE_menu_local_tasks_alter(&$data) {
foreach ($data['tabs'][0]['output'] as $key => $value) {
if ($value['#link']['path'] == 'node/%/view') {
unset($data['tabs'][0]['output'][$key]);
}
}
}
This is not the answer to the question of what the author asked. But somehow it might be useful for others user who facing the similar problem with me. Please let me know if this is not suitable to put in here.
I get the answer from #grayside and modified a bit to hide the view | edit tab from node based on the content type I want.
function MYMODULE_menu_alter(&$items) {
$items['node/%node/view']['access callback'] = 'MYMODULE_disable_node_view';
$items['node/%node/view']['access arguments'] = array(1);
}
function MYMODULE_disable_node_view($node){
if($node->type == 'product'){
return false;
}
}
product is the machine name of my content type, I don't want anywant to access it including root user.
The simplest solution to hide the tabs is to add this class in your theme css
.tabs{ display:none;}
Thanks for the last answer. But be aware of this detail: if you try it as-is it cannot work: literals should be just rounded with " or ', not both of them altogether. So it should be:
/**
* Implements hook_menu_local_tasks_alter() to unset unwanted tabs
*/
function MYMODULE_menu_local_tasks_alter(&$data) {
foreach ($data['tabs'][0]['output'] as $key => $value) {
if ($value['#link']['path'] == "node/%/view") {
unset($data['tabs'][0]['output'][$key]);
}
}
}
Once taken care of it, it works :)
D8 solution: If you want to hide all "local" tabs on certain pages, remember that "Tabs" is listed in the block library: find it in the "Content" region and exclude by content type, page URL or user role.

Why isn't $vars['node'] available in preprocess_page for some content types?

I am currently using drupal 6 for a site I'm working on. I have a MYTHEME_preprocess_page() function that adds a few variables to the page.tpl.php template from the taxonomy and from a cck field. It was working correctly for a bit, and then the $vars['node'] is empty, but only for 2 content types. The 'node' variable is available to the preprocess_page function in other content types.
I thought it was a problem with using the following code, but when I remove all of this, the 'node' variable is still empty.
function mytheme_preprocess_node(&$vars, $hook) {
$function = 'mytheme_preprocess_node'.'_'. $vars['node']->type;
if (function_exists($function)) {
$function(&$vars);
}
}
Does anyone know of any gotchas or bugs that might be removing the 'node' variable? I can't seem to figure out where I'm going wrong. I'm at a loss.
Here is my complete mytheme_preprocess_page() function.
function mytheme_preprocess_page(&$vars, $hook) {
if ($hook == 'node' || $hook == 'page') {
if (is_object($vars['node'])) {
// grab the header image if it exists to make it avaialble to the content header
$vars['header_image'] = _mytheme_get_header_image($vars);
// get the taxonomy term to put in the content header
if (count($vars['node']->taxonomy) > 0) {
$vars['tax_term'] = "<div class=\"terms\">" . _mytheme_get_first_taxonomy_term($vars['node']->taxonomy) . "</div>";
}
// add the teacher's credentials to the content header
if ($vars['node']->field_credentials[0]['view'] != '') {
$vars['teacher_credentials'] = '<span class="teacher-creds">' . $vars['node']->field_credentials[0]['view'] . '</span>';
}
}
}
}
After going through and disabling modules one-by-one, I determined that the problem is related to the module, node_breadcrumb. A similar issue was filed here: http://drupal.org/node/616100#comment-2199374
In the 3rd comment, you'll see a link to another issue with a resolution
For others that run into this, I had the same issue as a result of using the jQuery UI module. Disabling and re-enabling fixed it, and I could not track down the specific issue, but it appeared to be related to $static variables in some path check functions.
To others that stumble their way into here, I suggest you pull some of the more obvious modules right out of the module folder on your dev setup, see if things change, and then put them back in there until you figure it out.
Another option is to search for instances of _preprocess_page(, $variables['node'] and $vars['node'] to see if some contributed code is unwittingly unsetting a node when it shouldn't be.

Resources