$content_type, // No default, must pass a content type id name 'name' => st($content_name), // No default, must pass a content type display name 'module' => 'node', 'description' => st(''), 'custom' => TRUE, 'modified' => TRUE, 'has_title' => TRUE, 'has_body' => TRUE, 'title_label' => 'Title', 'body_label' => '', 'locked' => FALSE, 'min_word_count' => '0', 'orig_type' => '', 'help' => '', ); $type = array_merge($default, $properties); $type = (object)_node_type_set_defaults($type); node_type_save($type); } /** * Create a new field for an existing content type. * * @param $content_type Required. Existing content type (text id). * @param $field_name Required. A field name using only alpha-numeric and underscores. * @param $field_widget_type Required. A special name that uniquely identifies both the field type * and widget type. Each option item on the first page of the 'Add Field' form. * @param $properties Optional. An array of additional properties for the field. * * NOTE: Use install add_existing_field() to add an existing field. * * TIP: You can call print_r(install_get_widget_types()); to display a list of available * $field_widget_type options. */ function install_create_field($content_type, $field_name, $field_widget_type, $label, $properties = array()) { include_once(drupal_get_path('module', 'content') .'/content_admin.inc'); // Manage weight, so that fields are ordered as they are created. // Pass 'weight' => ##, on the properties array to reset. static $weight = 1; $weight = isset($properties['weight']) ? $properties['weight'] : $weight + 1; $widget_types = install_get_widget_types(); if (!array_key_exists($field_widget_type, $widget_types)) { drupal_set_message("'$field_widget_type' is not an available field/widget."); return; } // First step of creating the field - create the basic field. // Corresponds to first page of the Add field UI. $default_field_add = array( 'type_name' => $content_type, 'field_name' => $field_name, 'field_widget_type' => $field_widget_type, 'label' => $label, 'op' => 'Create field', 'submit' => 'Create field', 'form_id' => '_content_admin_field_add_new', ); // Create our new field. _content_admin_field_add_new_submit('_content_admin_field_add_new', $default_field_add); // Second step, update the field with our custom properties. // Corresponds to the second page (general config page) of content type creation. // We define defaults for a number of different field/widget types (eg. "referenceable_types" // is applicable to nodereference. These are ignored in cck when not applicable. $default_field_edit = array( 'type_name' => $content_type, 'field_name' => $field_name, 'label' => $label, 'weight' => $weight, 'description' => '', 'default_value_php' => '', 'group' => 0, 'required' => 0, 'multiple' => FALSE, 'text_processing' => 0, 'max_length' => '', 'allowed_values' => '', 'allowed_values_php' => '', 'rows' => 1, 'op' => 'Save field settings', 'submit' => 'Save field settings', 'form_id' => '_content_admin_field', 'referenceable_types' => array(), // Used in nodereference fields and userreference ); foreach($default_field_edit AS $key => $value) { if (isset($properties[$key])) { $default_field_edit[$key] = $properties[$key]; } } if (isset($properties['default_value'])) { $default_field_edit['default_value'][0]['value'] = $properties['default_value']; } // Derive the widget and type from the input type. $widget_parts = explode('-', $field_widget_type); $default_field_edit['field_type'] = $widget_parts[0]; $default_field_edit['widget_type'] = $widget_parts[1]; $default_field_edit['module'] = $widget_parts[0] .', optionwidgets'; _content_admin_field_submit('_content_admin_field_add_new', $default_field_edit); } /** * Returns an array of available fieldtype-widgettype arguments to * the $field_widget_type parameter of install_create_field() */ function install_get_widget_types() { $field_types = _content_field_types(); $widget_types = _content_widget_types(); $field_type_options = array(); foreach ($field_types as $field_name => $field_type) { foreach ($widget_types as $widget_name => $widget_type) { if (in_array($field_name, $widget_type['field types'])) { $field_type_options[$field_name .'-'. $widget_name] = $field_type['label'] .': '. $widget_type['label']; } } } return $field_type_options; } /** * Add an existing field to another content type. * * @param $content_type Required. Existing content type (text id). * @param $field_name Required. Existing field name (text id). */ function install_add_existing_field($content_type, $field_name) { // Defaults for passing to submit function. $form_values = array( 'field_name' => $field_name, 'type_name' => $content_type, 'op' => 'Add field', 'submit' => 'Add field', ); _content_admin_field_add_existing_submit('_content_admin_field_add_existing', $form_values); } /** * Create a new field group for an existing content type. * * @param $content_type Required. Existing content type (text id). * @param $group_name An alpha-numeric/underscore group name. * @param $label Required. A nice text name for your group. * @param $settings Optional. An array of settings, see the default array * defined in the function for an example. * @param $weight Optional, a standard weight integer. * */ function install_create_field_group($content_type, $group_name, $label, $settings = array(), $weight = 0) { if (!is_array($settings)) { // Default settings array. $settings = array( 'form' => array('style' => 'fieldset', 'description' => ''), 'display' => array('description' => '', 'teaser' => NULL, 'label' => NULL), ); } db_query("INSERT INTO {node_group} (type_name, group_name, label, settings, weight) VALUES ('%s', '%s', '%s', '%s', %d)", $content_type, $group_name, $label, serialize($settings), $weight); } /** * Assign fields to a field group. * * @param $content_type Required. Existing content type (text id). * @param $group_name Required. Existing group name (text id). * @param $fields Required. An array of field names. */ function install_fields_in_group($content_type, $group_name, $fields) { if (!is_array($fields)) { $fields = array($fields); } foreach ($fields AS $field_name) { db_query("INSERT INTO {node_group_fields} (type_name, group_name, field_name) VALUES ('%s', '%s', '%s')", $content_type, $group_name, $field_name); } } /* --- USER --- */ /** * Add a user */ function install_add_user($username, $password, $email, $roles = array(), $status = 1) { user_save( new stdClass(), array( 'name' => $username, 'pass' => $password, 'mail' => $email, 'roles' => $roles, 'status' => $status ) ); } /* --- CONTACT --- */ /** * Add a new contact category, including recipients and so on */ function install_contact_add_category($category, $recipients, $reply = '', $weight = 0, $selected = 0) { db_query("INSERT INTO {contact} (category, recipients, reply, weight, selected) VALUES ('%s', '%s', '%s', %d, %d)", $category, $recipients, $reply, $weight, $selected); } /* --- PROFILE FUNCTIONS --- */ /** * Given a funky array of profile fields, create them. */ function install_profile_field_add($data) { if (!is_array($data) || !isset($data['title']) || !isset($data['name'])) { return false; } $data['fid'] = db_next_id("{profile_fields}_fid"); $data['category'] = ($data['category']) ? $data['category'] : ''; $data['type'] = ($data['type']) ? $data['type'] : 'textfield'; $data['required'] = ($data['required']) ? $data['required'] : '0'; $data['register'] = ($data['register']) ? $data['register'] : '0'; $data['visibility'] = ($data['visibility']) ? $data['visibility'] : '0'; $data['explanation'] = ($data['explanation']) ? $data['explanation'] : ''; $fields = array_keys($data); // Prepare the query: foreach ($data as $key => $value) { if (in_array((string) $key, $fields)) { $k[] = db_escape_string($key); $v[] = $value; $s[] = "'%s'"; } } db_query("INSERT INTO {profile_fields} (". implode(", ", $k) .") VALUES (". implode(", ", $s) .")", $v); return $data['fid']; } /* --- ROLE --- */ /** * Add a role to the roles table. */ function install_add_role($name) { db_query("INSERT INTO {role} (name) VALUES ('%s')", $name); return install_get_rid($name); } /** * Get the role id for the role name */ function install_get_rid($name) { return db_result(db_query("SELECT rid FROM {role} WHERE name ='%s' LIMIT 1", $name)); } /** * Set the permission for a certain role */ function install_set_permissions($rid, $perms) { db_query('DELETE FROM {permission} WHERE rid = %d', $rid); db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, implode(', ', $perms)); } /* --- MENU --- */ /** * Create a new top-level menu * * @return integer The database ID of the newly created menu */ function install_menu_create_menu($title, $weight = 0) { $mid = db_next_id('{menu}_mid'); // Check explicitly for mid <= 2. If the database was improperly prefixed, // this would cause a nasty infinite loop or duplicate mid errors. // TODO: have automatic prefixing through an installer to prevent this. while ($mid <= 2) { $mid = db_next_id('{menu}_mid'); } db_query("INSERT INTO {menu} (mid, pid, title, weight, type) VALUES (%d, 0, '%s', %d, 115)", $mid, $title, $weight); // not sure if this is needed, but we've seen problems without it. menu_rebuild(); // this is important to add new items to this menu. return $mid; } /** * Get the menu ID, searching on path * * @return integer The database ID of a menu item based on its path */ function install_menu_get_mid($path) { // not sure if this is needed, but we've seen problems without it. menu_rebuild(); return db_result(db_query("SELECT mid FROM {menu} WHERE path = '%s' LIMIT 1", $path)); } /** * Get the menu ID of a root menu, based on title, e.g. Secondary links * * @return integer The database ID of the root menu that matches the $title */ function install_menu_get_root_menu($title) { return db_result(db_query("SELECT mid FROM {menu} WHERE title = '%s' LIMIT 1", $title)); } /** * Set an existing menu ID to a new parent */ function install_menu_set_menu($mid, $pid, $weight = 0, $type = 54) { db_query("UPDATE {menu} SET pid = %d, type = %d, weight = %d WHERE mid = %d", $pid, $type, $weight, $mid); menu_rebuild(); // not sure if this is needed, but we've seen problems without it. } /** * Create a new menu item * * @param $path Path of the new menu item * @param $title Title of the menu item (visible label for menu) * @param $pid Parent ID -- which menu the item is being added to * @param $description Description of the menu item (tooltip) * @param $weight Weight for positioning * @param $type Menu item type; new items are 118 by default * @return integer The database ID of the menu item */ function install_menu_create_menu_item($path, $title, $pid, $description = '', $weight = 0, $type = 118) { $menu = array( 'path' => $path, 'title' => st($title), 'pid' => $pid, 'description' => st($description), 'weight' => $weight, 'type' => $type ); menu_save_item($menu); menu_rebuild(); // not sure if this is needed, but we've seen problems without it return install_menu_get_mid($path); // this is important to add new items to this menu. } /** * Creates a batch of menu items * @param $items An array containing menu items (as arrays) * @param $pid Parent ID -- which menu the items are being added to */ function install_menu_create_menu_items($items, $pid) { foreach ($items as $item) { $mid = install_menu_create_menu_item($item['path'], $item['title'], $pid, $item['description'], $item['weight'], $item['type']); if (isset($items['children'])) { foreach ($item['children'] as $children) { install_menu_create_menu_items($children, $mid); } } } } /** * Update a menu item. * * @param $mid Menu item id * @param $properties A keyed array of only the values you want to change. * * @return FALSE if menu does not exist, otherwise return the status returned * by menu_save_item() in menu.module */ function install_menu_update_menu_item($mid, $properties) { $existing_item = menu_get_item($mid); if (empty($existing_item)) { drupal_set_message(t('Menu item '. $mid .' did not exist in install_menu_update_menu().')); return FALSE; } $edit = array_merge($existing_item, $properties); $edit['mid'] = $mid; // Tell menu this is an updated item. $edit['type'] = 54; $status = menu_save_item($edit); menu_rebuild(); return $status; } /** * Remove the specified filter from the specified format * @param $mid The ID of the menu item to disable * * NOTE: the module name + the delta is what uniquely identifies a filter */ function install_menu_disable_item($mid) { $item = menu_get_item($mid); $type = $item['type']; $type &= ~MENU_VISIBLE_IN_TREE; $type &= ~MENU_VISIBLE_IN_BREADCRUMB; $type |= MENU_MODIFIED_BY_ADMIN; db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $mid); drupal_set_message(t('The menu item has been disabled.')); // No redirection during install //drupal_goto('admin/build/menu'); } /* --- BLOCKS --- */ /** * Creates a new block. */ function install_add_block($module, $delta, $theme, $status, $weight, $region, $visibility, $pages, $custom, $throttle, $title) { db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, title) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, '%s')", $module, $delta, $theme, $status, $weight, $region, $visibility, $pages, $custom, $throttle, $title); if ($module == 'block') { $box = db_fetch_object(db_query('SELECT * FROM {boxes} WHERE bid=%d', $delta)); db_query("INSERT INTO {boxes} (bid, body, info, format) VALUES (%d, '%s', '%s', '%s')", $box->bid, $box->body, $box->info, $box->format); } } /** * Position an existing block inside a region of a theme. * * @param $theme A theme name, eg. 'garland' * @param $region Available region: usually one of 'header', 'footer', 'left', 'right', 'content' * @param $module The name of the module that provides the block * @param $delta The block id. * @param $weight Block order within the region. * * TIP: To identify the $module and $delta, go to an existing site * and visit the /admin/build/block page. Hover over the 'configure' * links - the module and delta are the last two parts of the * target url. */ function install_set_block($theme, $region, $module, $delta, $weight = 0) { block_admin_display_submit('block_admin_display', array(array('theme' => $theme, 'region' => $region, 'module' => $module, 'delta' => $delta, 'weight' => $weight))); } /** * Creates a new block role. */ function install_add_block_role($module, $delta, $rid) { db_query("INSERT INTO {blocks_roles} (module,delta,rid) VALUES ('%s', '%s', %d)", $module, $delta, $rid); } /* --- TINYMCE --- */ /** * Add roles to an existing TinyMCE profile identified by the profile name */ function install_tinymce_add_roles($name, $roles) { foreach ($roles as $role) { db_query("INSERT INTO {tinymce_role} (name, rid) VALUES ('%s', %d)", $name, $role); } } /** * Create a new TinyMCE profile and set the settings * * @param $name A text string identifying the profile * @param $settings An associative array containing key value pairs */ function install_tinymce_create_profile($name, $settings) { db_query("INSERT INTO {tinymce_settings} (name, settings) VALUES ('%s', '%s')", $name, serialize($settings)); } /* --- TAXONOMY --- */ /** * Given the name of a vocabulary, return its Vocab ID * * @param $name A text string identifying the vocabulary */ function install_get_vid($name) { // not guaranteed to be unique, hence the LIMIT return db_result(db_query("SELECT vid FROM {vocabulary} WHERE name = '%s' LIMIT 1", $name)); }; /** * Create a new taxonomy vocabulary * * @param $vocab_name The vocabulary name * @param $properties Optional. An array of additional properties. * @param $node_types Optional. An array of content types. * @return integer The database ID of the created vocabulary. */ function install_add_vocabulary($vocab_name, $properties = array(), $content_types = array()) { // Copy values to respective keys, as per taxonomy module. $content_types = array_flip($content_types); foreach ($content_types AS $type => $ignore_key) { $content_types[$type] = $type; } // Default properties so you don't have to pass anything. $default = array( 'name' => $vocab_name, 'description' => '', 'help' => '', 'hierarchy' => 0, // 0 = disabled; 1 = single; 2 = multiple 'relations' => FALSE, 'tags' => FALSE, 'required' => FALSE, 'weight' => 0, 'op' => 'Submit', 'submit' => 'Submit', ); $form_values = array_merge($default, $properties); $form_values['nodes'] = $content_types; taxonomy_save_vocabulary($form_values); return $form_values['vid']; } /** * Create a new taxonomy term * @param $vocab The vocabulary ID * @param $name The text name of the new term * @param $description Term description * @return integer The database ID of the created term */ function install_add_term($vocab, $name, $parent, $description) { $form_values = array( 'name' => $name, 'description' => $description, 'parent' => array($parent), 'vid' => $vocab, 'synonyms' => '', 'op' => 'Submit', 'weight' => 0, ); taxonomy_save_term($form_values); return $form_values['tid']; } /** * Assign a term to a node. * @param $vocab The vocabulary ID * @param $name The text name of the new term * * NOTE: does not check whether the assignment is valid. */ function install_assign_nid_tid($nid, $tid) { if (!$tid || !$nid) { return; } db_query('DELETE FROM {term_node} WHERE nid = %d AND tid = %d', $nid, $tid); db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid); } /* --- FILTER --- */ /** * Set the roles that can be used with the filter * @param $roles An array of role IDs * @param $format_id An integer of the format ID */ function install_format_set_roles($roles, $format_id) { $roles = implode(',',$roles); db_query("UPDATE {filter_formats} SET roles = '%s' WHERE format = %d", $roles, $format_id); } /** * Add a new input format * @param $name The human-readable name of the new format * @param $cache If this format is cacheable */ function install_add_format($name, $cache = 1) { $format_id = db_next_id('{filter_formats}_fid'); // Check explicitly for format_id <= 3. If the database was improperly prefixed, // this would cause a nasty infinite loop or duplicate mid errors. // TODO: have automatic prefixing through an installer to prevent this. while ($format_id <= 3) { $format_id = db_next_id('{filter_formats}_fid'); } db_query("INSERT INTO {filter_formats} (`format`, `name`, `roles`, `cache`) VALUES (%d, '%s', '', %d)", $format_id, $name, $cache); return $format_id; } /** * Remove the specified filter from the specified format * * @param $format_id The ID of the format to remove the filter from * @param $module The module this filter belongs to * @param $delta The delta of this filter * * NOTE: the module name + the delta is what uniquely identifies a filter */ function install_remove_filter($format_id, $module, $delta) { db_query("DELETE FROM {filters} WHERE format = %d AND module = '%s' AND delta = %d", $format_id, $module, $delta); } /** * Add a filter to an input format * * @param $format_id The ID of the format to add the filter to * @param $module The module this filter belongs to * @param $delta The delta of this filter * @param $weight The weight to be applied to this filter */ function install_add_filter($format_id, $module, $delta = 0, $weight = 0) { db_query("INSERT INTO {filters} (`format`, `module`, `delta`, `weight`) VALUES (%d, '%s', %d, %d)", $format_id, $module, $delta, $weight); } /* --- THEME --- */ /** * Example usage: * // Set site theme * install_disable_theme("garland"); * install_default_theme("mytheme"); */ /** * Enable theme * * @param $theme Unique string that is the name of theme */ function install_enable_theme($theme) { system_theme_data(); db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' and name = '%s'", $theme); system_initialize_theme_blocks($theme); } /** * Disable theme * * @param $theme Unique string that is the name of theme */ function install_disable_theme($theme) { system_theme_data(); db_query("UPDATE {system} SET status = 0 WHERE type = 'theme' and name ='%s'", $theme); } /** * Set default theme * * @param $theme Unique string that is the name of theme */ function install_default_theme($theme) { install_enable_theme($theme); variable_set('theme_default', $theme); } /** * Set admin theme * * @param $theme Unique string that is the name of theme */ function install_admin_theme($theme) { variable_set('admin_theme', $theme); } /* --- WORKFLOW AND ACTIONS --- */ /* * NOTE: It's been found that workflow implements very clean CRUD style * functions. The wrappers implemented here should serve as pointers to * the existence of these functions, sort of an education. Since these are * just wrappers, keep the space used to a minimum, please review the * workflow and actions modules for documentation of their functions. * * Might be worth more discussion: remove these wrappers? add docs?. */ /** * Create a workflow. * * @param $name Display name for workflow. * @param $roles An array of role IDs */ function install_workflow_create($name, $roles) { $wid = workflow_create($name); workflow_update($wid, $name, $roles); return $wid; } /** * Create workflow-to-content-type mappings. * * @param $content_to_workflows * Keyed array: 'content_type' => 'workflow_id' * */ function install_workflow_type_map_create($content_type, $workflow_id) { // Prevent workflow module destroying existing associations. Oh well. $type_map = array(); $result = db_query("SELECT wid, type FROM {workflow_type_map}"); while ($data = db_fetch_object($result)) { $type_map[$data->type] = $data->wid; } $type_map[$content_type] = $workflow_id; workflow_types_save($type_map); } /** * Create a workflow state */ function install_workflow_create_state($wid, $name, $weight = 0, $sysid = 0) { return workflow_state_save(array('wid' => $wid, 'state' => $name, 'sysid' => $sysid, 'weight' => $weight)); } /** * Create a workflow transition */ function install_workflow_add_transition_role($from, $to, $role) { workflow_transition_add_role($from, $to, $role); } /** * Create an configured action. * * @param $function The function name that implements an action, eg. 'action_send_email' * @param $description The description for this instance of an action * @param $params A keyed array of configuration parameters. * * NOTE: Non-configurable actions (eg. 'action_node_publish') do not need to be created. */ function install_action_create_action($function, $description, $params) { // $type is not configurable in the admin, so hide it from the install api and assign dynamically. $actions = actions_list(); $type = $actions[$function]['type']; return actions_save($function, $type, $params, $description); } /** * Register an action to a transition. */ function install_workflow_add_transition_action($transition_id, $action_id) { workflow_actions_save($transition_id, $action_id); }