array(
'type' => 'node',
'description' => t('Modify node fields'),
'configurable' => TRUE,
'behavior' => array('changes_node_property'),
'form properties' => array('#field_info'),
'rules_ignore' => TRUE,
));
}
/**
* Implementation of hook_theme().
* Called by VBO on its own hook_theme().
*/
function views_bulk_operations_fields_action_theme() {
return array(
'views_bulk_operations_fields_action_form' => array(
'arguments' => array('form' => NULL),
),
);
}
/**
* Action function.
*/
function views_bulk_operations_fields_action(&$node, $context) {
foreach ($context['#field_info'] as $field_name => $field) {
if (empty($context[$field_name . '_check'])) continue;
// Get the value, either by PHP evaluation or literally.
if (!empty($context[$field_name . '_code'])) {
$value = eval('?>' . $context[$field_name . '_code']);
}
else {
$value = $context[$field_name];
}
// Set the value.
if ($field['type'] == 'non_cck') { // our hacked definition
if (is_array($value)) foreach ($value as $v_key => $v_item) {
$node->$v_key = _views_bulk_operations_fields_action_token($v_item, $node, $field);
}
else {
$node->$field_name = _views_bulk_operations_fields_action_token($value, $node, $field);
}
if (is_array($field['submit'])) foreach ($field['submit'] as $function) {
if (!function_exists($function)) continue;
$function($node, $value, $field);
}
}
else { // CCK
if (empty($context[$field_name . '_add'])) {
$node->$field_name = _views_bulk_operations_fields_action_token($value, $node, $field);
}
else if (is_array($value)) {
// Adding to existing values: do it one by one.
foreach ($value as $v_delta => $v_item) {
if (is_string($v_delta)) {
$node->{$field_name}[$v_delta] = _views_bulk_operations_fields_action_token($v_item, $node, $field, $v_delta);
}
else {
$node->{$field_name}[] = _views_bulk_operations_fields_action_token($v_item, $node, $field, $v_delta);
}
}
}
}
}
}
/**
* Action form function.
*/
function views_bulk_operations_fields_action_form($context) {
module_load_include('inc', 'content', 'includes/content.node_form');
// This action form uses static-time settings. If they were not set, pull the defaults now.
if (!isset($context['settings'])) {
$context['settings'] = views_bulk_operations_fields_action_views_bulk_operations_form_options();
}
$form['#settings'] = $context['settings'];
$form['#theme'] = 'views_bulk_operations_fields_action_form';
$form['#node'] = (object)array('type' => NULL);
$form_state = array();
$weight = -100;
// Get the content types of the selected nodes if any. Otherwise, get all types.
if (isset($context['selection']) && isset($context['view'])) {
$nids = array_map('_views_bulk_operations_get_oid', $context['selection'], array_fill(0, count($context['selection']), $context['view']->base_field));
$result = db_query("SELECT DISTINCT type FROM {node} WHERE nid IN (%s)", implode(',', $nids));
}
else {
$result = db_query("SELECT type FROM {node_type}");
}
// For each type, get its fields.
$fields = array();
while ($type = db_result($result)) {
$fields += _views_bulk_operations_fields_action_non_cck($type);
$type_info = content_types($type);
$fields += $type_info['fields'];
}
if (empty($fields)) {
form_set_error('', t('The selected nodes do not have any editable fields. Please select other nodes and try again.'));
return array();
}
// Iterate on fields, creating the input widget for each.
foreach ($fields as $field) {
// Skip fields for which the user has no permission.
if (module_exists('content_permissions') &&
in_array('edit ' . $field['field_name'], module_invoke('content_permissions', 'perm')) &&
!user_access('edit ' . $field['field_name'])) continue;
// Skip fields that are not selected in VBO settings.
if (!empty($context['settings']['display_fields']) &&
!in_array($field['field_name'], $context['settings']['display_fields']) &&
!in_array(VBO_ACTION_FIELDS_ALL, $context['settings']['display_fields'])) continue;
// Set the default value in the synthesized node.
$form['#node']->{$field['field_name']} = empty($context[$field['field_name'] . '_check']) ? NULL : $context[$field['field_name']];
// The field info and widget.
if ($field['type'] == 'non_cck') { // is it our hacked definition?
$form += (array)$field['form'];
if (is_array($form['#node']->{$field['field_name']})) {
foreach ($form['#node']->{$field['field_name']} as $v_key => $v_item) {
$form[$field['field_name']][$v_key]['#default_value'] = $v_item;
}
}
else {
$form[$field['field_name']]['#default_value'] = $form['#node']->{$field['field_name']};
}
}
else { // no, it's CCK
$field['required'] = FALSE;
$form += (array)content_field_form($form, $form_state, $field);
}
if (empty($form[$field['field_name']])) continue;
// CCK needs this to properly process its fields.
$form['#field_info'][$field['field_name']] = $field;
// Adjust some settings on the field itself.
$form[$field['field_name']]['#weight'] = $weight++;
$form[$field['field_name']]['#prefix'] = '
',
);
}
}
// Special case for only one field: convert the checkbox into a value that's TRUE by default.
if (count($form['#field_info']) == 1) {
$field_name = key($form['#field_info']);
$form[$field_name . '_check'] = array('#type' => 'value', '#value' => TRUE);
}
return $form;
}
function theme_views_bulk_operations_fields_action_form($form) {
$output = '';
if (module_exists('token') && !empty($form['#settings']['show_tokens'])) {
$output .= t('
Using tokens
In text fields, you can use the following tokens:
', array('!tokens' => theme('token_help', 'node'))
);
drupal_add_js('misc/collapse.js');
}
$access = user_access('Use PHP input for field settings (dangerous - grant with care)');
if ($access && $form['#settings']['php_code']) {
$output .= t('
Using the Code widget
Will override the value specified in the Field widget.
Should include <?php ?> delimiters.
If in doubt, refer to devel.module \'Dev load\' tab on a content page to figure out the expected format.
The variables $node and $context are available to the script.
', array('@link_devel' => 'http://www.drupal.org/project/devel')
);
}
if (count($form['#field_info']) == 1) { // Special case for just one field: make the table more usable
$field_name = key($form['#field_info']);
$header = array();
if ($form[$field_name . '_add']['#type'] == 'checkbox') {
$row[] = drupal_render($form[$field_name . '_add']);
$header[] = array('data' => t('Add?'), 'title' => t('Checkboxes in this column allow you to add new values to multi-valued fields, instead of overwriting existing values.'));
}
$row[] = drupal_render($form[$field_name]);
$header[] = t('Field');
if ($access && $form['#settings']['php_code']) {
$row[] = drupal_render($form[$field_name . '_code']);
$header[] = t('Code');
}
if (count($header) == 1) {
$header = NULL;
}
$output .= theme('table', $header, array(array('class' => 'fields-action-row', 'id' => 'fields-action-row' . str_replace('_', '-', $field_name), 'data' => $row)));
}
else { // Many fields
drupal_add_js(drupal_get_path('module', 'views_bulk_operations') . '/fields.action.js');
$header = array(theme('table_select_header_cell'), t('Add?'), t('Field'));
if ($access && $form['#settings']['php_code']) {
$header[] = t('Code');
}
if (!empty($form['#field_info'])) foreach ($form['#field_info'] as $field_name => $field) {
$row = array(
'class' => 'fields-action-row',
'id' => 'fields-action-row-' . str_replace('_', '-', $field_name),
'data' => array(
drupal_render($form[$field_name . '_check']),
drupal_render($form[$field_name . '_add']),
drupal_render($form[$field_name]),
),
);
if ($access && $form['#settings']['php_code']) {
$row['data'][] = drupal_render($form[$field_name . '_code']);
}
$rows[] = $row;
}
$output .= theme('table', $header, $rows);
}
$output .= drupal_render($form);
return $output;
}
function views_bulk_operations_fields_action_validate($form, $form_state) {
$chosen = 0;
foreach ($form['#field_info'] as $field_name => $field) {
if (empty($form_state['values'][$field_name . '_check'])) continue;
$chosen++;
if (!empty($form_state['values'][$field_name . '_code'])) continue;
if ($field['type'] == 'non_cck') {
if (is_array($field['validate'])) foreach ($field['validate'] as $function) {
if (!function_exists($function)) continue;
$function($form_state['values'][$field_name], $field);
}
}
else {
$function = $field['module'] .'_field';
if (!function_exists($function)) continue;
$form['#node']->$field_name = $form_state['values'][$field_name];
$items = isset($form['#node']->$field_name) ? $form['#node']->$field_name : array();
$function('validate', $form['#node'], $field, $items, $form, NULL);
content_field('validate', $form['#node'], $field, $items, $form, NULL);
}
}
if (!$chosen) {
form_set_error('', t('You must select at least one field to modify.'));
}
}
function views_bulk_operations_fields_action_submit($form, $form_state) {
$values = array();
foreach ($form['#field_info'] as $field_name => $field) {
if ($field['type'] == 'non_cck') {
$values[$field_name] = $form_state['values'][$field_name];
}
else {
unset($form_state['values'][$field_name][$field_name .'_add_more']);
$values[$field_name] = content_set_empty($field, $form_state['values'][$field_name]);
}
$values[$field_name . '_check'] = $form_state['values'][$field_name . '_check'];
$values[$field_name . '_add'] = $form_state['values'][$field_name . '_add'];
if (isset($form_state['values'][$field_name . '_code'])) {
$values[$field_name . '_code'] = $form_state['values'][$field_name . '_code'];
}
}
$values['#field_info'] = $form['#field_info'];
return $values;
}
/**
* Implementation of hook_views_bulk_operations_fields().
* Return field definitions for common Drupal node fields:
* array(
* field_name => array(
* 'label' => label to display in admin settings
* 'form' => array of form elements
* 'validate' => array of functions to handle validation of submitted values for the form elements
* 'submit' => array of functions to handle further node changes after values have been copied over
* ),
* )
*/
function views_bulk_operations_views_bulk_operations_fields($type) {
$fields = array();
$fields['title'] = array(
'label' => t('Title'),
'form' => array(
'title' => array(
'#type' => 'textfield',
'#title' => t('Title'),
),
),
);
$fields['body_field'] = array(
'label' => t('Body'),
'form' => array(
'body_field' => array(
'#tree' => TRUE,
'body' => array(
'#type' => 'textarea',
'#title' => t('Body'),
),
'format' => filter_form(FILTER_FORMAT_DEFAULT, NULL, array('body_field', 'format')),
),
),
);
$fields['publishing'] = array(
'label' => t('Publishing options'),
'form' => array(
'publishing' => array(
'#tree' => TRUE,
'publishing_options' => array(
'#value' => t('Publishing options') . ':',
'#prefix' => '',
'#ignore' => TRUE,
),
'status' => array(
'#type' => 'checkbox',
'#title' => t('Published'),
),
'promote' => array(
'#type' => 'checkbox',
'#title' => t('Promoted to front page'),
),
'sticky' => array(
'#type' => 'checkbox',
'#title' => t('Sticky at top of lists'),
),
),
),
);
$fields['authoring'] = array(
'label' => t('Authoring information'),
'form' => array(
'authoring' => array(
'#tree' => TRUE,
'name' => array(
'#type' => 'textfield',
'#title' => t('Authored by'),
'#maxlength' => 60,
'#autocomplete_path' => 'user/autocomplete',
'#weight' => -1,
'#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
),
'date' => array(
'#type' => 'textfield',
'#title' => t('Authored on'),
'#maxlength' => 25,
'#description' => t('Format: %time. Leave blank to use the time of form submission.', array('%time' => !empty($node->date) ? $node->date : format_date($node->created, 'custom', 'Y-m-d H:i:s O'))),
),
),
),
'validate' => array('_views_bulk_operations_field_action_validate_authoring'),
'submit' => array('_views_bulk_operations_field_action_submit_authoring'),
);
if (module_exists('comment')) {
$fields['comment'] = array(
'label' => t('Comment settings'),
'form' => array(
'comment' => array(
'#title' => t('Comment settings'),
'#type' => 'radios',
'#parents' => array('comment'),
'#options' => array(t('Disabled'), t('Read only'), t('Read/Write')),
),
),
);
}
if (module_exists('locale')) {
$fields['language'] = array(
'label' => t('Language'),
'form' => array(
'language' => array(
'#type' => 'select',
'#title' => t('Language'),
'#options' => array('' => t('Language neutral')) + locale_language_list('name'),
),
),
);
}
return $fields;
}
/**
* Validate function for authoring form element.
*/
function _views_bulk_operations_field_action_validate_authoring($value, $field) {
if (!($account = user_load(array('name' => $value['name'])))) {
form_set_error('authoring][name', t('This username does not exist. Please select an existing user.'));
}
}
/**
* Submit function for authoring form element.
*/
function _views_bulk_operations_field_action_submit_authoring(&$node, $value, $field) {
if ($account = user_load(array('name' => $node->name))) {
$node->uid = $account->uid;
}
else {
$node->uid = 0;
}
$node->created = !empty($node->date) ? strtotime($node->date) : time();
}
/**
* VBO settings form function.
*/
function views_bulk_operations_fields_action_views_bulk_operations_form_options() {
$options['php_code'] = FALSE;
$options['display_fields'] = array(VBO_ACTION_FIELDS_ALL);
$options['show_tokens'] = TRUE;
return $options;
}
function views_bulk_operations_fields_action_views_bulk_operations_form($options) {
$form['php_code'] = array(
'#type' => 'checkbox',
'#title' => t('Show PHP code area'),
'#description' => t('Check this ON to show a textarea for each field to allow the user to write a PHP script that will populate the value of this field.'),
'#default_value' => $options['php_code'],
);
$form['show_tokens'] = array(
'#type' => 'checkbox',
'#title' => t('Show available tokens'),
'#description' => t('Check this ON to show tokens that are available for replacement in text fields. Only works with Token module enabled.'),
'#default_value' => $options['show_tokens'],
);
$fields = array(VBO_ACTION_FIELDS_ALL => t('- All fields -'));
foreach (node_get_types() as $type => $info) {
foreach (_views_bulk_operations_fields_action_non_cck($type) as $field) {
$fields[$field['field_name']] = $field['label'] .' ('. $field['field_name'] .')';
}
}
foreach (content_fields() as $field) {
$fields[$field['field_name']] = $field['widget']['label'] .' ('. $field['field_name'] .')';
}
if (empty($options['display_fields'])) {
$options['display_fields'] = array(VBO_ACTION_FIELDS_ALL);
}
$form['display_fields'] = array(
'#type' => 'select',
'#title' => t('Display fields'),
'#options' => $fields,
'#multiple' => TRUE,
'#description' => t('Select which field(s) the action form should present to the user.'),
'#default_value' => $options['display_fields'],
);
return $form;
}
function views_bulk_operations_fields_action_views_bulk_operations_form_validate($form, $form_state) {
if (empty($form_state['values']['display_fields'])) {
form_set_error($form_state['values']['_error_element_base'] . 'display_fields', t('You must select at least one field to be shown to the user.'));
}
}
function _views_bulk_operations_fields_action_token($value, $node, $field, $delta = NULL) {
if (module_exists('token')) {
if (isset($delta) && isset($field['columns']) && is_array($value)) {
foreach (array_keys($field['columns']) as $column) {
if (isset($value[$column])) {
$value[$column] = token_replace($value[$column], 'node', $node);
}
}
}
else if (is_array($value)) foreach ($value as $v_delta => $v_item) {
if (is_array($v_item) && isset($field['columns'])) foreach (array_keys($field['columns']) as $column) {
if (isset($v_item[$column])) {
$value[$v_delta][$column] = token_replace($v_item[$column], 'node', $node);
}
}
else {
$value[$v_delta] = token_replace($v_item, 'node', $node);
}
}
else {
$value = token_replace($value, 'node', $node);
}
}
return $value;
}
function _views_bulk_operations_fields_action_non_cck($type, $reset = FALSE) {
static $fields = NULL;
if (empty($fields[$type]) || $reset) {
foreach (module_invoke_all('views_bulk_operations_fields', $type) as $field_name => $field) {
$field['field_name'] = $field_name;
$field['type'] = 'non_cck';
$fields[$type][$field_name] = $field;
}
}
drupal_alter('views_bulk_operations_fields', $fields, $type);
return $fields[$type];
}