Get current page/url in a hook - drupal

In hook_css_alter, I want to disable style-sheets on specific pages.
Was ok for the front page requirement with following snippet:
function morin_css_alter(&$css) {
if(drupal_is_front_page()){
foreach ($css as $data => $item) {
unset($css[$data]);
}
}
}
Now I need to remove specific styles on a photo-album page. I have thought of a few ways to do this, but I'd like to do it the drupal way.
The closest function I have found to do this is drupal_get_destination() ,
I don't think it's meant for this but it does return the current path in an array, as shown by the following snippet added in css_alter hook.
echo " PATH = " . var_dump(drupal_get_destination());
Output: PATH = array(1) { ["destination"]=> string(6) "photos" }
Is this the recommended way of getting the path from inside a function/hook, or is there some variable in global namespace I should use instead?

You want http://api.drupal.org/api/drupal/includes--bootstrap.inc/function/request_path/7.
For Drupal 6, one has to use $_GET['q'].

Related

Replace Wordpress URL domain in HTML output (for SEO optimisation) [duplicate]

WordPress has great filter support for getting at all sorts of specific bits of content and modifying it before output. Like the_content filter, which lets you access the markup for a post before it's output to the screen.
I'm trying to find a catch-all filter that gives me one last crack at modifying the final markup in its entirety before output.
I've browsed the list of filters a number of times, but nothing jumps out at me:
https://codex.wordpress.org/Plugin_API/Filter_Reference
Anyone know of one?
WordPress doesn't have a "final output" filter, but you can hack together one. The below example resides within a "Must Use" plugin I've created for a project.
Note: I haven't tested with any plugins that might make use of the "shutdown" action.
The plugin works by iterating through all the open buffer levels, closing them and capturing their output. It then fires off the "final_output" filter, echoing the filtered content.
Sadly, WordPress performs almost the exact same process (closing the open buffers), but doesn't actually capture the buffer for filtering (just flushes it), so additional "shutdown" actions won't have access to it. Because of this, the below action is prioritized above WordPress's.
wp-content/mu-plugins/buffer.php
<?php
/**
* Output Buffering
*
* Buffers the entire WP process, capturing the final output for manipulation.
*/
ob_start();
add_action('shutdown', function() {
$final = '';
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
// that buffer's output into the final output.
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
$final .= ob_get_clean();
}
// Apply any filters to the final output
echo apply_filters('final_output', $final);
}, 0);
An example of hooking into the final_output filter:
<?php
add_filter('final_output', function($output) {
return str_replace('foo', 'bar', $output);
});
Edit:
This code uses anonymous functions, which are only supported in PHP 5.3 or newer. If you're running a website using PHP 5.2 or older, you're doing yourself a disservice. PHP 5.2 was released in 2006, and even though Wordpress (edit: in WP version < 5.2) STILL supports it, you should not use it.
The question is may be old, but I have found a better way to do it:
function callback($buffer) {
// modify buffer here, and then return the updated code
return $buffer;
}
function buffer_start() { ob_start("callback"); }
function buffer_end() { ob_end_flush(); }
add_action('wp_head', 'buffer_start');
add_action('wp_footer', 'buffer_end');
Explanation
This plugin code registers two actions – buffer_start and buffer_end.
buffer_start is executed at the end of the header section of the html. The parameter, the callback function, is called at the end of the output buffering. This occurs at the footer of the page, when the second registered action, buffer_end, executes.
The callback function is where you add your code to change the value of the output (the $buffer variable). Then you simply return the modified code and the page will be displayed.
Notes
Be sure to use unique function names for buffer_start, buffer_end, and callback, so they do not conflict with other functions you may have in plugins.
AFAIK, there is no hook for this, since the themes uses HTML which won't be processed by WordPress.
You could, however, use output buffering to catch the final HTML:
<?php
// example from php.net
function callback($buffer) {
// replace all the apples with oranges
return (str_replace("apples", "oranges", $buffer));
}
ob_start("callback");
?>
<html><body>
<p>It's like comparing apples to oranges.</p>
</body></html>
<?php ob_end_flush(); ?>
/* output:
<html><body>
<p>It's like comparing oranges to oranges.</p>
</body></html>
*/
#jacer, if you use the following hooks, the header.php also gets included.
function callback($buffer) {
$buffer = str_replace('replacing','width',$buffer);
return $buffer;
}
function buffer_start() { ob_start("callback"); }
function buffer_end() { ob_end_flush(); }
add_action('after_setup_theme', 'buffer_start');
add_action('shutdown', 'buffer_end');
I was using the top solution of this post (by kfriend) for a while. It uses an mu-plugin to buffer the whole output.
But this solution breaks the caching of wp-super-cache and no supercache-files are generated when i upload the mu-plugin.
So: If you are using wp-super-cache, you can use the filter of this plugin like this:
add_filter('wp_cache_ob_callback_filter', function($buffer) {
$buffer = str_replace('foo', 'bar', $buffer);
return $buffer;
});
Modified https://stackoverflow.com/users/419673/kfriend answer.
All code will be on functions.php. You can do whatever you want with the html on the "final_output" filter.
On your theme's 'functions.php'
//we use 'init' action to use ob_start()
add_action( 'init', 'process_post' );
function process_post() {
ob_start();
}
add_action('shutdown', function() {
$final = '';
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
// that buffer's output into the final output.
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
$final .= ob_get_clean();
}
// Apply any filters to the final output
echo apply_filters('final_output', $final);
}, 0);
add_filter('final_output', function($output) {
//this is where changes should be made
return str_replace('foo', 'bar', $output);
});
You might try looking in the wp-includes/formatting.php file. For example, the wpautop function.
If you are looking for doing something with the entire page, look at the Super Cache plugin. That writes the final web page to a file for caching. Seeing how that plug-in works may give you some ideas.
Indeed there was a discusussion recently on the WP-Hackers mailing list about the topic of full page modification and it seems the consensus was that output buffering with ob_start() etc was the only real solution. There was also some discussion about the upsides and downsides of it: http://groups.google.com/group/wp-hackers/browse_thread/thread/e1a6f4b29169209a#
To summarize: It works and is the best solution when necessary (like in the WP-Supercache plugin) but slows down overall speeds because your content isn't allowed to be sent to the browser as its ready, but instead has to wait for the full document to be rendered (for ob_end() ) before it can be processed by you and sent to the browser.
To simplify previous answers, just use this in functions.php:
ob_start();
add_action('shutdown', function () {
$html = ob_get_clean();
// ... modify $html here
echo $html;
}, 0);
I've been testing the answers here now for a while, and since the cache breaking thing is still an issue, I came up with a slightly different solution. In my tests no page cache broke. This solution has been implemented into my WordPress plugin OMGF (which has 50k+ users right now) and no issues with page cache breaking has been reported.
First, we start an output buffer on template redirect:
add_action('template_redirect', 'maybe_buffer_output', 3);
function maybe_buffer_output()
{
/**
* You can run all sorts of checks here, (e.g. if (is_admin()) if you don't want the buffer to start in certain situations.
*/
ob_start('return_buffer');
}
Then, we apply our own filter to the HTML.
function return_buffer($html)
{
if (!$html) {
return $html;
}
return apply_filters('buffer_output', $html);
}
And then we can hook into the output by adding a filter:
add_filter('buffer_output', 'parse_output');
function parse_output($html)
{
// Do what you want. Just don't forget to return the $html.
return $html;
}
Hope it helps anyone.
I have run into problems with this code, as I end up with what seems to be the original source for the page so that some plugins has no effect on the page. I am trying to solve this now - I haven't found much info regarding best practises for collecting the output from WordPress.
Update and solution:
The code from KFRIEND didnt work for me as this captures unprocessed source from WordPress, not the same output that ends up in the browser in fact. My solution is probably not elegant using a globals variable to buffer up the contents - but at least I know get the same collected HTML as is delivered to the browser. Could be that different setups of plugins creates problems but thanks to code example by Jacer Omri above I ended up with this.
This code is in my case located typically in functions.php in theme folder.
$GLOBALS['oldschool_buffer_variable'] = '';
function sc_callback($data){
$GLOBALS['final_html'] .= $data;
return $data;
}
function sc_buffer_start(){
ob_start('sc_callback');
}
function sc_buffer_end(){
// Nothing makes a difference in my setup here, ob_get_flush() ob_end_clean() or whatever
// function I try - nothing happens they all result in empty string. Strange since the
// different functions supposedly have very different behaviours. Im guessing there are
// buffering all over the place from different plugins and such - which makes it so
// unpredictable. But that's why we can do it old school :D
ob_end_flush();
// Your final HTML is here, Yeeha!
$output = $GLOBALS['oldschool_buffer_variable'];
}
add_action('wp_loaded', 'sc_buffer_start');
add_action('shutdown', 'sc_buffer_end');
If you want to modify the output, you can use template_include:
add_filter( 'template_include', static function ( $template ) {
if ( basename( $template ) === 'foo-template.php' ) {
echo str_replace( 'foo', 'bar', file_get_contents( $template ) );
}
return null;
} );
If instead you want to override the output completely, you can use the action template_redirect.
add_action( 'template_redirect', static function () {
wp_head();
echo 'My output.';
wp_footer();
exit;
} );

Drupal 7 Views custom view template fields

I've successfully created a custom view template for my Drupal 7 site but am having issues adding attributes to the content which is outputted. I've searched high and low for the answer to this but to no avail.
I have a view called: views-view-fields--homepage-articles.tpl.php
I am printing content like :
$fields['title']->content
This is fine and expected, and outputs:
Title
But I want to add classes to it - how? I'm thinking I need to write a hook, but I cannot find this documented anywhere. At the moment my solution is a string replace:
<?php print str_replace('<a ', '<a class="brand-blue uppercase nodecoration"', $fields['title']->content); ?>
As you can imagine, this is not a satisfactory or long-term solution.
Many thanks!
You should be able to add the classes to the field using template_preprocess_views_view_fields().
Edit: Couldn't do it the way I thought, but you can overwrite the output of the field like so:
function MY_THEME_preprocess_views_view_fields(&$vars) {
$view = $vars['view'];
if ($view->name == 'node_listing') {
foreach ($vars['fields'] as $id => $field) {
if ($id == 'title') {
$field_output = l($view->result[$view->row_index]->node_title, 'node/'. $view->result[$view->row_index]->nid, array('attributes' => array('class' => 'brand-blue uppercase nodecoration')));
$vars['fields'][$id]->content = $field_output;
}
}
}
}
Have you tried using Semantic Views? https://drupal.org/project/semanticviews - that way you can override the classes within the UI instead of template files, may suit your needs better.

Adding space to select option in form alter

I have taxonomy terms hierarchy and I am using them as a filter in a view. It is showing hierarchy in the selectbox, but child terms appearing with hyphen(-). I have tried to drop hyphen in form alter, and I did, but I couldn't replace it blank space.
if ($form_id == 'views_exposed_form') {
$i = 0;
foreach ($form['field_region_tid']["#options"] as $op) {
foreach ($op->option as $key => $arr) {
if ($arr != null) {
$form['field_region_tid']["#options"][$i]->option[$key] = str_replace("-"," ", $arr);
}
}
$i++;
}
}
How can I put blank space at the beginning of the child options. Or should I do some other way?
Thanks!
From the form_id I get that it is a form generated by views. If so, the code inside the if condition never gets called because your module is executed after the views module due to the weight of both modules. To fix that:
Open your database manager (PhpMyAdmin in most cases) and open system table.
Then change the weight for your module to something larger than 10, because it is the default weight for the views module and you need you module to be executed after the views module.
Hope this helps... Muhammad.
if the problem is when your hook is called the answer lies in
hook_module_implements_alter()
but it is not as you say. Your code looks fine,
Have you tried
str_replace("-"," ", $arr);
?

Insert code right after body tag using theme functions

I am trying to add a piece of code at the begining of every page in a Drupal site.
Since I have more than one page template, I want to do this programatically... but am not succeeding.
I am still new and, though I get the gist of hooks, theme functions, and the such, I just can't figure the correct way to achieve this.
So far I've overriden the theme_preprocess_page(&$vars) to add the necessary css and js:
function mytheme_preprocess_page(&$vars) {
if(condition) {
drupal_add_js(drupal_get_path('module', 'mymodule').'/js/modal.js');
}
}
How can I now add html code in every drupal page, preferably just after the opening bodytag or in any other starting section, via a function in the template.phpfile?
Thank you
In your preprocess function, any variable set, will be available in your page.tpl.php file.
function mytheme_preprocess_page(&$vars) {
if (condition) {
$vars['foo'] = '<div id="bar">TEST</div>';
}
}
then, in your page templates:
<body>
<?php print !empty($foo) ? $foo : ''; ?>
...
Had a look at https://www.drupal.org/project/google_tag. This is how they did it:
/**
* Implements hook_page_alter().
*
* Adds a post_render callback
*/
function MYMODULE_page_alter(&$page) {
$page['#post_render'][] = 'MYMODULE_CALLBACK';
}
/**
* Implements callback_post_render().
*
* Inserts JavaScript snippet immediately following the opening body tag.
*/
function MYMODULE_CALLBACK(&$children, $elements) {
$script = '<script type="text/javascript">console.log(\'hello world\');</script>';
// Insert snippet after the opening body tag.
$children = preg_replace('#<body[^>]*>#', '$0' . $script, $children, 1);
return $children;
}
This should keep you from having to modify any code in your templates:
function MY_MODULE_page_build(&$page)
{
$page['page_bottom']['my-markup'] = array('#markup' => '<div>My Markup Here</div>');
}
My approach finally was overriding the first rendered block in the page, in my case the Language Switcher.
Since I already was overriding it to customize it, it wasn't too much of a big deal, but it is anyway an ugly way to achieve that.
<?php
function mytheme_languageswitcher($links) {
// inserting this here like a virus in a dna strip
if(condition) {
drupal_add_js(drupal_get_path('module', 'mymodule').'/js/modal.js');
}
// the *real* code for the language switcher override
}
?>
Since the Language Switcher is rendered in every page, it works. The day the language switcher stops being displayed for whatever reason, this solution will FAIL.
You can add it to the footer with an option passed into the drupal_add_js function.
function THEMENAME_preprocess_page(&$variables) {
if (condition) {
drupal_add_js(drupal_get_path('theme', 'THEMENAME') . '/PATH/TO/FILE.js', array('scope' => 'footer'));
}
}
This will end up printing just before the closing body tag via the $page_bottom variable in the template html.tpl.php.
Another way to do it is to use the native drupal methods drupal_add_js and drupal_get_js.
// first, add your JS with a custom "scope" (before process phase)
<?php
drupal_add_js($tag_js, array(
'type' => 'inline',
'group' => JS_GROUP_TAGS,
'every_page' => TRUE,
'scope' => 'body_start',
'weight' => 1,
));
?>
// ugly way : add the drupal_get_js directly into html.tpl.php (but for testing, it's useful):
<body>
<?php print drupal_get_js('body_start'); ?>
...
</body>
// A cleaner way : use an intermediate variable, in a process method
// Exactly like template_process_html, in theme.inc
<?php
function MYMODULEORTHEME_process_html(&$variables){
$variables['js_body_start'] .= drupal_get_js('body_start');
}
?>
Enjoy :)

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