I'm looking for a way to make changes in rendered HTML parts, when they are the result of an AJAX request, just before they are returned to the user.
Currently it concerns Views, but its own hooks don't meet my need since the changes I want to make don't regard Views results but Views admin responses.
Anyway I'd like to be as generic as possible, so I could intervene upon any AJAX return.
Thanks in advance for any idea.
Issue when using the interesting solution proposed by Andre-B
It seemed to perfectly meet my need so I introduced it gradually into my module in order to test successively each of its aspects.
First I added only a simple trace to my module, using FirePHP:
<?php
function mymodule_init() {
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$buffered_output = &drupal_static('mymodule_output_buffered', true);
// AJAX request
fb($buffered_output,'init');
}
}
function mymodule_exit() {
$buffered_output = &drupal_static('mymodule_output_buffered', false);
if ($buffered_output) {
fb($buffered_output,'exit');
}
}
The results were:
- no trace when AJAX not involved
for an AJAX request, the trace was:
- init: 1
- exit: 1
In other words, it worked as expected, without any error message and normally delivering the HTML output.
Then, in order to now control what was uncertain about the warning stated in the hook_exit page:
This hook MUST NOT print anything because by the time it runs the response is already sent to the browser.
I simply changed for the following:
<?php
function mymodule_init() {
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$buffered_output = &drupal_static('mymodule_output_buffered', true);
// AJAX request
ob_start();
}
}
function mymodule_exit() {
$buffered_output = &drupal_static('mymodule_output_buffered', false);
if ($buffered_output) {
print ob_get_clean();
}
}
What I expected was, either:
- if there was a real issue regarding the warning, it should merely NOT return the expected HTML output
- otherwise all should have worked as usual
But in fact I got the error message:
Call to undefined function MYFUNCTION (which belongs to MYMODULE, see below)...
At the opposite of what was expected, this relies to the OTHER warning stated by the hook_exit page:
If you implement this hook and see an error like 'Call to undefined function', it is likely that you are depending on the presence of a module which has not been loaded yet. It is not loaded because Drupal is still in bootstrap mode.
At this stage, I don't understand what happens:
- At a first view, seems that introducing
ob_start()
andob_get_clean()
should not change anything to which modules are already loaded or not. In other words, if it fails here, it should have failed with the previous test too - Secondly, the allegedly undefined function (say
undef_func()
) belongs to my module: it resides in an additional file, which is loaded by mymodule.module (usingmodule_load_include()
), while thehook_exit()
function is also located in mymodule.module, soundef_func()
should have already been loaded whenhook_exit()
is called
To be more clear, here is (part of) the mymodule schema:
file: mymodule.module
<?php
module_load_include('inc', 'mymodule', 'mymodule.data');
module_load_include('inc', 'mymodule', 'mymodule.core');
function mymodule_init() {
# ...
}
function mymodule_exit() {
# ...
}
# other mymodule hooks...
file: mymodule.core
<?php
function undef_func() {
# ...
}
# other mymodule core funcs...
For now I don't see how to understand what is happening...
Issue solved, but a mistery remains
I tested more, adding a lot of trace points to identify how and when the files were loaded.
Then I first realized that, since I was connected with administration menu active, every call to a mysite url caused successively:
- the entire page to be returned as expected
- then an AJAX request to be sent by admin_menu
And I discovered that, for some reason, this AJAX request only invokes hook_init()
, while any non-AJAX call and all other AJAX requests invoke both hook_init()
and hook_exit()
.
It was apparently the reason why I got the error mentioned above.
Another strange thing is that, systematically, after an error had been fired:
- flushing class registry caused a normal page to be rendered without any error
- then F5 fired the error again
And so on, cyclically, without any change in the code! I can't figure out how this can be explained.
In the other hand, once this behaviour known, I could act to avoid this case, and do the job where I need it.
So definitely, this solution works!