We're converting some sites over to a Drupal 6 multi site and we have a number of existing pages that make heavy use of PHP.

What's the easiest way to include these scripts, assuming that they may want to live in different menus in different languages, and that we want these pages to also work like other pages on our site (e.g. take advantage of Rules, Views, CCK etc).

  • Using hook_menu() to create a MENU_CALLBACK seems to mean we couldn't treat them like other pages (have people edit titles/content, use Views/Rules etc).

  • Using hook_nodeapi() to add the PHP only works if it is always at the end (or beginning) of any content.

  • Using the PHP filter to include a file works, but means editors would need the right to use PHP.

The solution I'm leaning towards is creating a custom filter that replaces a keyword/token with a file/function so editors would add {{FOO_SCRIPT}} to their page and the relevant code would get included.

Is there a better way?


3 Answers 3


Normally I do heavy php lifting on nodes in hook_preprocess_node(&$vars) and parse / include content in the $vars.

hook_nodeapi() is of course another way to go about it and your additional content will be available in many different $operations, I don't use hook_nodeapi() unless I'm altering data that gets saved, deleted etc within nodes - for display layer stuff hook_preprocess_node() always treats me well.

If you could expand on what sort of preprocessing and content you are including in nodes I'm sure we could go into more details into the best suited solution :)

Update: Given the variety of the tasks you aim to use (APIs, Additional DB Calls, or User Input Parsing etc), I'd definately recommend you use hook_nodeapi so you have the fine grained control over the context. preprocess is view layer only and I feel as though you will likely want to hook the nodeapi(&$node, $op = 'load') so as to make your data entries high level enough to have the information widely accessible (like $node->your_custom_api_field in a node.tpl.php)

I highly recommend that you try to stay with Drupal's conventions as much as possible. Using database functions etc. Checkout the http://drupal.org/project/data module and possibly http://drupal.org/project/schema which both help working with your own tables (and the data module even helps expose that table to views so you can stay with Drupal core more!)


My advice is to create a custom module for each data module you have so it can have it use it's own hook_nodeapi and any other hook's that may be required :)

  • Sorry; didn't want to bog these down with details, but these are pages, for example, that look up the nearest X by zip code, or interface with third part APIs, or look up data in various tables and then manipulate it based on user choices (not directly related to the table) and create PDFs on the fly etc. Some of these could arguably be recreated with wrestling with Views/CCK/Feeds but in general that would take a load of time, and these pages already exist in good, maintainable, efficient php form. They're all different pages from a large, multipurpose website.
    – Apemantus
    Apr 13, 2011 at 15:18
  • updated to give my 2 cents on how I'd approach your issue
    – electblake
    Apr 15, 2011 at 16:13

Are you thinking of something like token filter?

Have the PHP functions available as tokens using the token api and then allow people to enter these tokens in your page.

  • Yes, that's pretty much exactly what I was thinking. The more I think about it, this seems to be the only way to do it, without letting people accidentally mangle things (for example, I can happily let editors use a WYSIWYG editor on the content for these pages). I guess all I need is to create my own filter based on token filter which calls hook_token_values with lots of token "types" so that it's not calling a load of functions/including files each time it's called.
    – Apemantus
    Apr 13, 2011 at 15:27

If you are talking of nodes, and you just need to convert the existing nodes that were using PHP as input filter, then I would suggest you to do what was done from Drupal.org.

  • Create a custom module that implements hook_nodeapi().
  • In the implementation of that hook, add the code that, when the operation is "view"
    • checks the node ID of the node being viewed;
    • when the node ID matches the ID of one of those nodes that were using the PHP filter, it executes the code that was contained in the node body.

The code should be something similar to the following one.

function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if ($op == 'view') {
    switch ($node->nid) {
      case 23:
        // Change the content of $node->content['body']['#value'].
      // ... 

If the purpose is to allow some code to be used also to change the content of nodes created even after the site has been converted, or to keep the pages existing before the site is converted editable, then you have two possibilities.

  • You use the code I reported before, but instead of changing the content of $node->content['body']['#value'], you append the result of the executed code to $node->content['body']['#value'].
  • You use a filter module. Custom filter, for example, allows the users with the right permission (which should not be given to the normal editor users) to define a string that needs to be replaced (using a regular expression) and the replacement string that can be either the string returned from PHP code, or a string containing $1, $2, etc (in other words, a string similar to the string used by preg_replace()).

Another module that is similar to Custom filter is Regex Filters, but I have never used it, and I don't know if it allows to use a PHP code as replacement rule.

In general is preferable to not use drupal_eval() (or eval()); this means that it is preferable to create a custom module that alters the node content through hook_nodeapi(), or a custom module that implements an input filter and replaces some defined string with the result returned from PHP code that is not passed to eval() in any way.
The problem with the input filter is that users could use the string replaced by the module in contexts where the string used to replace it should not appear. To resolve this problem, you could install Better Formats, which allows to control the allowed formats per content type, and decide which users can use a specific input format.

  • The current sites do not use Drupal, but are based on a variety of cmses/homerolled solutions we're trying to consolidate. The problem with using hook_nodeapi() is if content is like <intro test><php code><outro text> then I can't insert the code in the middle. (Unless I add an "after" field to my content type. I guess then I could maintain a list of nids - the issue in part is that as it's a multi site (using Domain Access) there might be (say) 8 scripts on 20 sites, so it's a slight (only slight mind) pain to update hook_nodeapi() every time a new site comes online.)
    – Apemantus
    Apr 13, 2011 at 15:33
  • @Apemantus The problem with the input filter is that users could use the replaced string also where they should not; the input filter should check in which nodes the string is used, and how much times. There is a module that allows to select which input formats can be selected for a specific content type, but this would not resolve the "multiple instances" problem.
    – apaderno
    Apr 13, 2011 at 15:51
  • true, and I could instigate an additional layer of checking; at the moment, editors will probably only be able to edit but not publish revisions, with publishing left to trusted web admins, which should stop people using {{FOO_SCRIPT}} rather than {{BAR_SCRIPT}} (or more likely {{FOO_SCRIP} or someother mispelling - but I take your point that control is less accurate in this situation.
    – Apemantus
    Apr 13, 2011 at 16:47
  • @Apemantus Input filters are also used for comments, and in other contexts too; CCK can use input formats for the content of a CCK field. That is also the reason why input filters don't get a node reference. Those are other points to consider.
    – apaderno
    Apr 13, 2011 at 16:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.