Hi this is probably a really basic question, but hopefully you guys can help me out...

I have a javascript client application (Separate to my main Drupal 7 website) and rather than maintaining a duplicate select list with a large number of values, I would like to use an AJAX call to a PHP file on the Drupal server which will render the HTML for the list I need.

The list is configured as a custom field (Text List type).

Can I create a PHP file in the root of the website, and include the required module files?

I've been trying with the following code and get a blank response:-

<?php
define('DRUPAL_ROOT', getcwd());
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
require_once DRUPAL_ROOT . '/modules/field/field.module';
echo render($content['field_name']);
drupal_exit();
?>

Comments

entropea’s picture

I've just realised that the $content array is null, as it's not in the context.

So my question is what should I call instead of "render($content..."?

goofus’s picture

Hello,
You extend Drupal's functionality by creating a "module". https://drupal.org/developing/modules

You implement hook_menu (http://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_menu/7) to map a request url (AKA path) to you custom code. In your code, you would use the Drupal API (http://api.drupal.org/api/drupal) to select the appropriate data, format the output (e.g. JSON) and return a response.

If you peruse Drupal's source code, you'll find a huge collection of working examples :)

Good Luck :

entropea’s picture

... render just the raw HTML for a field.

My module code is:-

// AJAX menu to call render list
 function enact_menu() {
  $items['render-location-list'] = array(
    'title' => 'AJAX Render List', // Required, won't actually be displayed anywhere
    'access callback' => TRUE, // Normal for an AJAX call
    'page callback' => 'enact_render_location_list',
    'type' => MENU_CALLBACK
  );

  return $items;
}

function enact_render_location_list() {
  //neither of these work:-
  print render(field_info_field('field_location'));
  print render($content['field_name']);
}

There is no $node or $entity context, so what is the best way to output the HTML fragment for a List field?

The custom field is linked to the User entity... But I don't have specific user to load, just want to render the field attached to the entity...

Anonymous’s picture

This seems like a lot of work just to get a list, but there's probably a way.
What do you get when you use this function? http://api.drupal.org/api/drupal/includes%21common.inc/function/entity_g...

nevets’s picture

What are you trying to make a list of?

goofus’s picture

Hello,
Your enact_render_location_list() method is missing logic. You need to retrieve the data (E,G. your reference to User entity) before you can do anything (E.G. like rendering it).

You can use something like user_load http://api.drupal.org/api/drupal/modules!user!user.module/function/user_load/7

You have the menu part down!! Good job, now you just need to complete the logic. Retrieve the data and then format it (I'm not sure what you plan on doing with the data, however you have to get it first :) )

Anonymous’s picture

I think the problem is that he wants to retrieve the field without reference to a particular user or node, so user_load won't work. Is that correct?

entropea’s picture

Thanks everyone for your suggestions, they really helped. @Clive from drupal.stackexchange.com offered the following code which solved the problem for me (No specific user or node, just needed the field rendering). For info, here's the code:

*********************************
You could definitely bootstrap Drupal in a standalone file, but if you're doing it inside the same document root as the Drupal installation you'd be better off implementing a custom menu path in a module, and using the callback for that path to output the necessary value.

If you print directly from a page callback function and don't return anything, the standard theme wrappers won't be included and you'll just be left with the value you've printed.

A basic example might look like this:

function MYMODULE_menu() {
  $items['custom-path'] = array(
    'title' => 'Custom page', // Required, won't actually be displayed anywhere
    'access arguments' => array('access content'), 
    // 'access callback' => TRUE, // This is an alternative to the access arguments if you don't need any access control for this path
    'page callback' => 'MYMODULE_ajax_page',
    'type' => MENU_CALLBACK
  );

  return $items;
}

function MYMODULE_ajax_page() {
  $output = function_to_produce_field_output();

  print $output;
}

After you clear Drupal's caches any request for http://mysite.com/custom-path should produce the un-themed results from your page callback; you can then use that path as your AJAX callback.

You might also want to look at drupal_add_http_header() to set an appropriate content type before you print the output.

As far as getting the field output goes, it's a bit of a pain but this should work:

$entity_type = 'user';
$bundle = 'user';
$field_name = 'field_field_name';

// Get field info for the allowed values
$field_info = field_info_field($field_name);

// Get instance info for label/required/description/default value
$field_instance = field_info_instance($entity_type, $field_name, $bundle);

// Build the select list
$select = array(
  '#type' => 'select',
  '#value' => $field_instance['default_value'],
  '#options' => $field_info['settings']['allowed_values'],
  '#required' => $field_instance['required']
);

// Build the element wrapper
$wrapper = array(
  '#title' => t($field_instance['label']),
  '#description' => t($field_instance['description']),
  '#children' => theme('select', array('element' => $select))
);

// Get the fully rendered element
$rendered = theme('form_element', array('element' => $wrapper));

print $rendered;

I no longer need to maintain fields in three separate systems, just use Drupal as the master for all the client webapps ;) It's missing security, but none of the list values are sensitive so it doesn't really matter.

goofus’s picture

Hello,
Great work. Please edit your original post and change the subject line so that it either ends with or begins with "[SOLVED]". That way other folks can find the solution :)

Your are welcome :) Glad to have helped :)